From 1c18c020923f44d58f1969d706625e90e1fecc81 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 17 Dec 2024 19:40:00 +0300 Subject: [PATCH] move Chunks from Level to Player --- dev/tests/example.lua | 4 +- src/TestMainloop.cpp | 4 +- src/frontend/hud.cpp | 49 +++++---- src/frontend/hud.hpp | 4 +- src/frontend/screens/LevelScreen.cpp | 10 +- src/graphics/render/BlockWrapsRenderer.cpp | 11 +- src/graphics/render/BlockWrapsRenderer.hpp | 6 +- src/graphics/render/ChunksRenderer.cpp | 61 ++++++----- src/graphics/render/ChunksRenderer.hpp | 3 + src/graphics/render/Decorator.cpp | 4 +- src/graphics/render/ParticlesRenderer.cpp | 10 +- src/graphics/render/ParticlesRenderer.hpp | 3 + src/graphics/render/WorldRenderer.cpp | 13 ++- src/logic/BlocksController.cpp | 87 ++++++++++----- src/logic/BlocksController.hpp | 9 +- src/logic/ChunksController.cpp | 39 ++++--- src/logic/ChunksController.hpp | 14 +-- src/logic/LevelController.cpp | 25 +++-- src/logic/LevelController.hpp | 2 +- src/logic/PlayerController.cpp | 24 ++--- src/logic/scripting/lua/libs/libblock.cpp | 4 +- src/logic/scripting/lua/libs/libentity.cpp | 12 ++- .../scripting/lua/libs/libgeneration.cpp | 2 +- src/logic/scripting/lua/libs/libhud.cpp | 3 +- src/logic/scripting/lua/libs/libworld.cpp | 14 +-- .../lua/usertypes/lua_type_voxelfragment.cpp | 2 +- src/objects/Entities.cpp | 2 +- src/objects/Player.cpp | 6 +- src/physics/PhysicsSolver.cpp | 28 ++--- src/physics/PhysicsSolver.hpp | 6 +- src/voxels/Chunks.cpp | 8 ++ src/voxels/Chunks.hpp | 2 + src/voxels/GlobalChunks.cpp | 5 + src/voxels/GlobalChunks.hpp | 3 + src/voxels/blocks_agent.cpp | 102 ++++++++++++++++++ src/voxels/blocks_agent.hpp | 41 +++++++ src/world/Level.cpp | 22 ---- src/world/Level.hpp | 5 - src/world/generator/VoxelFragment.cpp | 15 +-- src/world/generator/VoxelFragment.hpp | 6 +- 40 files changed, 450 insertions(+), 220 deletions(-) diff --git a/dev/tests/example.lua b/dev/tests/example.lua index f7147d06..0435b6cd 100644 --- a/dev/tests/example.lua +++ b/dev/tests/example.lua @@ -5,11 +5,9 @@ test.reconfig_packs({"base"}, {}) test.new_world("demo", "2019", "core:default") local pid = player.create("Xerxes") assert(player.get_name(pid) == "Xerxes") -test.sleep_until(function() return world.count_chunks() >= 9 end, 1000) +test.sleep_until(function() return block.get(0, 0, 0) >= 0 end, 1000) print(world.count_chunks()) -timeit(10000000, block.get, 0, 0, 0) - block.destruct(0, 0, 0, pid) assert(block.get(0, 0, 0) == 0) test.close_world(true) diff --git a/src/TestMainloop.cpp b/src/TestMainloop.cpp index 33487059..100c0b51 100644 --- a/src/TestMainloop.cpp +++ b/src/TestMainloop.cpp @@ -49,6 +49,8 @@ void TestMainloop::setLevel(std::unique_ptr level) { engine.getPaths()->setCurrentWorldFolder(fs::path()); controller = nullptr; } else { - controller = std::make_unique(&engine, std::move(level)); + controller = std::make_unique( + &engine, std::move(level), nullptr + ); } } diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 1a2d8315..e6b1ecb9 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -106,7 +106,7 @@ std::shared_ptr HudElement::getNode() const { std::shared_ptr Hud::createContentAccess() { auto content = frontend.getLevel().content; auto indices = content->getIndices(); - auto inventory = player->getInventory(); + auto inventory = player.getInventory(); size_t itemsCount = indices->items.count(); auto accessInventory = std::make_shared(0, itemsCount); @@ -120,7 +120,7 @@ std::shared_ptr Hud::createContentAccess() { inventory->move(copy, indices); }, [=](uint, ItemStack& item) { - inventory->getSlot(player->getChosenSlot()).set(item); + inventory->getSlot(player.getChosenSlot()).set(item); }); InventoryBuilder builder; @@ -132,7 +132,7 @@ std::shared_ptr Hud::createContentAccess() { } std::shared_ptr Hud::createHotbar() { - auto inventory = player->getInventory(); + auto inventory = player.getInventory(); auto content = frontend.getLevel().content; SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr); @@ -148,7 +148,7 @@ std::shared_ptr Hud::createHotbar() { static constexpr uint WORLDGEN_IMG_SIZE = 128U; -Hud::Hud(Engine* engine, LevelFrontend& frontend, Player* player) +Hud::Hud(Engine* engine, LevelFrontend& frontend, Player& player) : engine(engine), assets(engine->getAssets()), gui(engine->getGUI()), @@ -177,7 +177,7 @@ Hud::Hud(Engine* engine, LevelFrontend& frontend, Player* player) uicamera->flipped = true; debugPanel = create_debug_panel( - engine, frontend.getLevel(), *player, allowDebugCheats + engine, frontend.getLevel(), player, allowDebugCheats ); debugPanel->setZIndex(2); gui->add(debugPanel); @@ -246,12 +246,12 @@ void Hud::processInput(bool visible) { void Hud::updateHotbarControl() { if (!inventoryOpen && Events::scroll) { - int slot = player->getChosenSlot(); + int slot = player.getChosenSlot(); slot = (slot - Events::scroll) % 10; if (slot < 0) { slot += 10; } - player->setChosenSlot(slot); + player.setChosenSlot(slot); } for ( int i = static_cast(keycode::NUM_1); @@ -259,17 +259,17 @@ void Hud::updateHotbarControl() { i++ ) { if (Events::jpressed(i)) { - player->setChosenSlot(i - static_cast(keycode::NUM_1)); + player.setChosenSlot(i - static_cast(keycode::NUM_1)); } } if (Events::jpressed(keycode::NUM_0)) { - player->setChosenSlot(9); + player.setChosenSlot(9); } } void Hud::updateWorldGenDebugVisualization() { auto& level = frontend.getLevel(); - auto& chunks = *level.chunks; + const auto& chunks = *player.chunks; auto generator = frontend.getController()->getChunksController()->getGenerator(); auto debugInfo = generator->createDebugInfo(); @@ -318,9 +318,10 @@ void Hud::updateWorldGenDebugVisualization() { void Hud::update(bool visible) { const auto& level = frontend.getLevel(); + const auto& chunks = *player.chunks; auto menu = gui->getMenu(); - debugPanel->setVisible(player->debug && visible); + debugPanel->setVisible(player.debug && visible); if (!visible && inventoryOpen) { closeInventory(); @@ -337,7 +338,7 @@ void Hud::update(bool visible) { } if (blockUI) { - voxel* vox = level.chunks->get(blockPos.x, blockPos.y, blockPos.z); + voxel* vox = chunks.get(blockPos.x, blockPos.y, blockPos.z); if (vox == nullptr || vox->id != currentblockid) { closeInventory(); } @@ -355,7 +356,7 @@ void Hud::update(bool visible) { if (visible) { for (auto& element : elements) { - element.update(pause, inventoryOpen, player->debug); + element.update(pause, inventoryOpen, player.debug); if (element.isRemoved()) { onRemove(element); } @@ -363,8 +364,8 @@ void Hud::update(bool visible) { } cleanup(); - debugMinimap->setVisible(player->debug && showGeneratorMinimap); - if (player->debug && showGeneratorMinimap) { + debugMinimap->setVisible(player.debug && showGeneratorMinimap); + if (player.debug && showGeneratorMinimap) { updateWorldGenDebugVisualization(); } } @@ -375,7 +376,7 @@ void Hud::openInventory() { showExchangeSlot(); inventoryOpen = true; - auto inventory = player->getInventory(); + auto inventory = player.getInventory(); auto inventoryDocument = assets->get("core:inventory"); inventoryView = std::dynamic_pointer_cast(inventoryDocument->getRoot()); inventoryView->bind(inventory, content); @@ -422,7 +423,9 @@ void Hud::openInventory( closeInventory(); } auto& level = frontend.getLevel(); + const auto& chunks = *player.chunks; auto content = level.content; + blockUI = std::dynamic_pointer_cast(doc->getRoot()); if (blockUI == nullptr) { throw std::runtime_error("block UI root element must be 'inventory'"); @@ -436,10 +439,10 @@ void Hud::openInventory( if (blockinv == nullptr) { blockinv = level.inventories->createVirtual(blockUI->getSlotsCount()); } - level.chunks->getChunkByVoxel(block.x, block.y, block.z)->flags.unsaved = true; + chunks.getChunkByVoxel(block.x, block.y, block.z)->flags.unsaved = true; blockUI->bind(blockinv, content); blockPos = block; - currentblockid = level.chunks->get(block.x, block.y, block.z)->id; + currentblockid = chunks.require(block.x, block.y, block.z).id; add(HudElement(hud_element_mode::inventory_bound, doc, blockUI, false)); } @@ -481,7 +484,7 @@ void Hud::openPermanent(UiDocument* doc) { auto invview = std::dynamic_pointer_cast(root); if (invview) { - invview->bind(player->getInventory(), frontend.getLevel().content); + invview->bind(player.getInventory(), frontend.getLevel().content); } add(HudElement(hud_element_mode::permanent, doc, doc->getRoot(), false)); } @@ -571,7 +574,7 @@ void Hud::draw(const DrawContext& ctx){ uishader->uniformMatrix("u_projview", uicamera->getProjView()); // Crosshair - if (!pause && !inventoryOpen && !player->debug) { + if (!pause && !inventoryOpen && !player.debug) { DrawContext chctx = ctx.sub(batch); chctx.setBlendMode(BlendMode::inversion); auto texture = assets->get("gui/crosshair"); @@ -629,7 +632,7 @@ void Hud::updateElementsPosition(const Viewport& viewport) { exchangeSlot->setPos(glm::vec2(Events::cursor)); } hotbarView->setPos(glm::vec2(width/2, height-65)); - hotbarView->setSelected(player->getChosenSlot()); + hotbarView->setSelected(player.getChosenSlot()); } bool Hud::isInventoryOpen() const { @@ -661,7 +664,7 @@ void Hud::setPause(bool pause) { } Player* Hud::getPlayer() const { - return player; + return &player; } std::shared_ptr Hud::getBlockInventory() { @@ -684,7 +687,7 @@ void Hud::setDebugCheats(bool flag) { gui->remove(debugPanel); debugPanel = create_debug_panel( - engine, frontend.getLevel(), *player, allowDebugCheats + engine, frontend.getLevel(), player, allowDebugCheats ); debugPanel->setZIndex(2); gui->add(debugPanel); diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index 5594664a..6d9d3f92 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -75,7 +75,7 @@ class Hud : public util::ObjectsKeeper { std::unique_ptr uicamera; gui::GUI* gui; LevelFrontend& frontend; - Player* player; + Player& player; /// @brief Is any overlay/inventory open bool inventoryOpen = false; @@ -131,7 +131,7 @@ class Hud : public util::ObjectsKeeper { void showExchangeSlot(); void updateWorldGenDebugVisualization(); public: - Hud(Engine* engine, LevelFrontend& frontend, Player* player); + Hud(Engine* engine, LevelFrontend& frontend, Player& player); ~Hud(); void update(bool hudVisible); diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 9470e7e0..e39d4736 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -44,9 +44,9 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr levelPtr) auto menu = engine->getGUI()->getMenu(); menu->reset(); - controller = std::make_unique(engine, std::move(levelPtr)); - auto player = level->players->get(0); + controller = + std::make_unique(engine, std::move(levelPtr), player); playerController = std::make_unique( settings, level, @@ -60,21 +60,21 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr levelPtr) worldRenderer = std::make_unique( engine, *frontend, player ); - hud = std::make_unique(engine, *frontend, player); + hud = std::make_unique(engine, *frontend, *player); decorator = std::make_unique( *engine, *controller, *worldRenderer, assets, *player ); keepAlive(settings.graphics.backlight.observe([=](bool) { - controller->getLevel()->chunks->saveAndClear(); + player->chunks->saveAndClear(); worldRenderer->clear(); })); keepAlive(settings.camera.fov.observe([=](double value) { player->fpCamera->setFov(glm::radians(value)); })); keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){ - controller->getLevel()->chunks->saveAndClear(); + player->chunks->saveAndClear(); worldRenderer->clear(); })); diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp index 3ad30ad8..d19b1f1e 100644 --- a/src/graphics/render/BlockWrapsRenderer.cpp +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -14,15 +14,18 @@ #include "window/Window.hpp" #include "world/Level.hpp" -BlockWrapsRenderer::BlockWrapsRenderer(const Assets& assets, const Level& level) - : assets(assets), level(level), batch(std::make_unique(1024)) { +BlockWrapsRenderer::BlockWrapsRenderer( + const Assets& assets, const Level& level, const Chunks& chunks +) + : assets(assets), + level(level), + chunks(chunks), + batch(std::make_unique(1024)) { } BlockWrapsRenderer::~BlockWrapsRenderer() = default; void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) { - const auto& chunks = *level.chunks; - auto textureRegion = util::get_texture_region(assets, wrapper.texture, ""); auto& shader = assets.require("entity"); diff --git a/src/graphics/render/BlockWrapsRenderer.hpp b/src/graphics/render/BlockWrapsRenderer.hpp index 728e664a..9d6184b9 100644 --- a/src/graphics/render/BlockWrapsRenderer.hpp +++ b/src/graphics/render/BlockWrapsRenderer.hpp @@ -10,6 +10,7 @@ class Assets; class Player; class Level; +class Chunks; class DrawContext; struct BlockWrapper { @@ -20,6 +21,7 @@ struct BlockWrapper { class BlockWrapsRenderer { const Assets& assets; const Level& level; + const Chunks& chunks; std::unique_ptr batch; std::unordered_map> wrappers; @@ -27,7 +29,9 @@ class BlockWrapsRenderer { void draw(const BlockWrapper& wrapper); public: - BlockWrapsRenderer(const Assets& assets, const Level& level); + BlockWrapsRenderer( + const Assets& assets, const Level& level, const Chunks& chunks + ); ~BlockWrapsRenderer(); void draw(const DrawContext& ctx, const Player& player); diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index f669cfea..fe955bee 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -20,19 +20,22 @@ size_t ChunksRenderer::visibleChunks = 0; class RendererWorker : public util::Worker, RendererResult> { const Level& level; + const Chunks& chunks; BlocksRenderer renderer; public: RendererWorker( const Level& level, + const Chunks& chunks, const ContentGfxCache& cache, const EngineSettings& settings - ) : level(level), + ) : level(level), + chunks(chunks), renderer(settings.graphics.chunkMaxVertices.get(), *level.content, cache, settings) {} RendererResult operator()(const std::shared_ptr& chunk) override { - renderer.build(chunk.get(), level.chunks.get()); + renderer.build(chunk.get(), &chunks); if (renderer.isCancelled()) { return RendererResult { glm::ivec2(chunk->x, chunk->z), true, MeshData()}; @@ -44,29 +47,36 @@ public: }; ChunksRenderer::ChunksRenderer( - const Level* level, + const Level* level, + const Chunks& chunks, const Assets& assets, const Frustum& frustum, - const ContentGfxCache& cache, + const ContentGfxCache& cache, const EngineSettings& settings -) : level(*level), - assets(assets), - frustum(frustum), - settings(settings), - threadPool( - "chunks-render-pool", - [&](){return std::make_shared(*level, cache, settings);}, - [&](RendererResult& result){ - if (!result.cancelled) { - auto meshData = std::move(result.meshData); - meshes[result.key] = ChunkMesh { - std::make_unique(meshData.mesh), - std::move(meshData.sortingMesh) - }; - } - inwork.erase(result.key); - }, settings.graphics.chunkMaxRenderers.get()) -{ +) + : level(*level), + chunks(chunks), + assets(assets), + frustum(frustum), + settings(settings), + threadPool( + "chunks-render-pool", + [&]() { + return std::make_shared( + *level, chunks, cache, settings + ); + }, + [&](RendererResult& result) { + if (!result.cancelled) { + auto meshData = std::move(result.meshData); + meshes[result.key] = ChunkMesh { + std::make_unique(meshData.mesh), + std::move(meshData.sortingMesh)}; + } + inwork.erase(result.key); + }, + settings.graphics.chunkMaxRenderers.get() + ) { threadPool.setStopOnFail(false); renderer = std::make_unique( settings.graphics.chunkMaxVertices.get(), @@ -83,7 +93,7 @@ const Mesh* ChunksRenderer::render( ) { chunk->flags.modified = false; if (important) { - auto mesh = renderer->render(chunk.get(), level.chunks.get()); + auto mesh = renderer->render(chunk.get(), &chunks); meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { std::move(mesh.mesh), std::move(mesh.sortingMeshData) }; @@ -131,7 +141,7 @@ void ChunksRenderer::update() { const Mesh* ChunksRenderer::retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ) { - auto chunk = level.chunks->getChunks()[index]; + auto chunk = chunks.getChunks()[index]; if (chunk == nullptr || !chunk->flags.lighted) { return nullptr; } @@ -163,7 +173,6 @@ const Mesh* ChunksRenderer::retrieveChunk( void ChunksRenderer::drawChunks( const Camera& camera, Shader& shader ) { - const auto& chunks = *level.chunks; const auto& atlas = assets.require("blocks"); atlas.getTexture()->bind(); @@ -232,7 +241,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { frameid++; bool culling = settings.graphics.frustumCulling.get(); - const auto& chunks = level.chunks->getChunks(); + const auto& chunks = this->chunks.getChunks(); const auto& cameraPos = camera.position; const auto& atlas = assets.require("blocks"); diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 859bca9e..a25c4241 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -20,6 +20,7 @@ class Level; class Camera; class Shader; class Assets; +class Chunks; class Frustum; class BlocksRenderer; class ContentGfxCache; @@ -42,6 +43,7 @@ struct RendererResult { class ChunksRenderer { const Level& level; + const Chunks& chunks; const Assets& assets; const Frustum& frustum; const EngineSettings& settings; @@ -57,6 +59,7 @@ class ChunksRenderer { public: ChunksRenderer( const Level* level, + const Chunks& chunks, const Assets& assets, const Frustum& frustum, const ContentGfxCache& cache, diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 2f01955f..a3ef140b 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -85,7 +85,7 @@ void Decorator::update( int index = currentIndex; currentIndex = (currentIndex + BIG_PRIME) % UPDATE_BLOCKS; - const auto& chunks = *level.chunks; + const auto& chunks = *player.chunks; const auto& indices = *level.content->getIndices(); int lx = index % UPDATE_AREA_DIAMETER; @@ -108,7 +108,7 @@ void Decorator::update(float delta, const Camera& camera) { for (int i = 0; i < ITERATIONS; i++) { update(delta, pos, camera.position); } - const auto& chunks = *level.chunks; + const auto& chunks = *player.chunks; const auto& indices = *level.content->getIndices(); auto iter = blockEmitters.begin(); while (iter != blockEmitters.end()) { diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index 0e2292a5..80057352 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -16,12 +16,17 @@ size_t ParticlesRenderer::visibleParticles = 0; size_t ParticlesRenderer::aliveEmitters = 0; ParticlesRenderer::ParticlesRenderer( - const Assets& assets, const Level& level, const GraphicsSettings* settings + const Assets& assets, + const Level& level, + const Chunks& chunks, + const GraphicsSettings* settings ) : batch(std::make_unique(4096)), level(level), + chunks(chunks), assets(assets), - settings(settings) {} + settings(settings) { +} ParticlesRenderer::~ParticlesRenderer() = default; @@ -44,7 +49,6 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { const auto& right = camera.right; const auto& up = camera.up; - const auto& chunks = *level.chunks; bool backlight = settings->backlight.get(); std::vector unusedTextures; diff --git a/src/graphics/render/ParticlesRenderer.hpp b/src/graphics/render/ParticlesRenderer.hpp index 46509d96..3fe692e5 100644 --- a/src/graphics/render/ParticlesRenderer.hpp +++ b/src/graphics/render/ParticlesRenderer.hpp @@ -10,12 +10,14 @@ class Texture; class Assets; class Camera; +class Chunks; class MainBatch; class Level; struct GraphicsSettings; class ParticlesRenderer { const Level& level; + const Chunks& chunks; const Assets& assets; const GraphicsSettings* settings; std::unordered_map> particles; @@ -29,6 +31,7 @@ public: ParticlesRenderer( const Assets& assets, const Level& level, + const Chunks& chunks, const GraphicsSettings* settings ); ~ParticlesRenderer(); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index a0fd4c83..4455e451 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -68,21 +68,24 @@ WorldRenderer::WorldRenderer( lineBatch(std::make_unique()), batch3d(std::make_unique(BATCH3D_CAPACITY)), modelBatch(std::make_unique( - MODEL_BATCH_CAPACITY, assets, *level.chunks, engine->getSettings() + MODEL_BATCH_CAPACITY, assets, *player->chunks, engine->getSettings() )), particles(std::make_unique( - assets, level, &engine->getSettings().graphics + assets, level, *player->chunks, &engine->getSettings().graphics )), texts(std::make_unique(*batch3d, assets, *frustumCulling)), guides(std::make_unique()), chunks(std::make_unique( &level, + *player->chunks, assets, *frustumCulling, frontend.getContentGfxCache(), engine->getSettings() )), - blockWraps(std::make_unique(assets, level)) { + blockWraps( + std::make_unique(assets, level, *player->chunks) + ) { auto& settings = engine->getSettings(); level.events->listen( EVT_CHUNK_HIDDEN, @@ -362,7 +365,7 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { int x = std::floor(player->currentCamera->position.x); int y = std::floor(player->currentCamera->position.y); int z = std::floor(player->currentCamera->position.z); - auto block = level.chunks->get(x, y, z); + auto block = player->chunks->get(x, y, z); if (block && block->id) { const auto& def = level.content->getIndices()->blocks.require(block->id); @@ -381,7 +384,7 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { batch3d->begin(); shader.uniformMatrix("u_projview", glm::mat4(1.0f)); shader.uniformMatrix("u_apply", glm::mat4(1.0f)); - auto light = level.chunks->getLight(x, y, z); + auto light = player->chunks->getLight(x, y, z); float s = Lightmap::extract(light, 3) / 15.0f; glm::vec4 tint( glm::min(1.0f, Lightmap::extract(light, 0) / 15.0f + s), diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index bcc1f728..3c0b64c0 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -1,5 +1,7 @@ #include "BlocksController.hpp" +#include + #include "content/Content.hpp" #include "items/Inventories.hpp" #include "items/Inventory.hpp" @@ -11,12 +13,15 @@ #include "voxels/Chunk.hpp" #include "voxels/Chunks.hpp" #include "voxels/voxel.hpp" +#include "voxels/blocks_agent.hpp" #include "world/Level.hpp" #include "world/World.hpp" +#include "objects/Player.hpp" +#include "objects/Players.hpp" -BlocksController::BlocksController(const Level& level, Lighting& lighting, uint padding) +BlocksController::BlocksController(const Level& level, Lighting* lighting, uint padding) : level(level), - chunks(*level.chunks), + chunks(*level.chunksStorage), lighting(lighting), randTickClock(20, 3), blocksTickClock(20, 1), @@ -34,7 +39,7 @@ void BlocksController::updateSides(int x, int y, int z) { } void BlocksController::updateSides(int x, int y, int z, int w, int h, int d) { - voxel* vox = chunks.get(x, y, z); + voxel* vox = blocks_agent::get(chunks, x, y, z); const auto& def = level.content->getIndices()->blocks.require(vox->id); const auto& rot = def.rotations.variants[vox->state.rotation]; const auto& xaxis = rot.axisX; @@ -62,8 +67,10 @@ void BlocksController::breakBlock( onBlockInteraction( player, glm::ivec3(x, y, z), def, BlockInteraction::destruction ); - chunks.set(x, y, z, 0, {}); - lighting.onBlockSet(x, y, z, 0); + blocks_agent::set(chunks, x, y, z, 0, {}); + if (lighting) { + lighting->onBlockSet(x, y, z, 0); + } scripting::on_block_broken(player, def, glm::ivec3(x, y, z)); if (def.rt.extended) { updateSides(x, y, z , def.size.x, def.size.y, def.size.z); @@ -75,7 +82,7 @@ void BlocksController::breakBlock( void BlocksController::placeBlock( Player* player, const Block& def, blockstate state, int x, int y, int z ) { - auto voxel = chunks.get(x, y, z); + auto voxel = blocks_agent::get(chunks, x, y, z); if (voxel == nullptr) { return; } @@ -85,8 +92,10 @@ void BlocksController::placeBlock( onBlockInteraction( player, glm::ivec3(x, y, z), def, BlockInteraction::placing ); - chunks.set(x, y, z, def.rt.id, state); - lighting.onBlockSet(x, y, z, def.rt.id); + blocks_agent::set(chunks, x, y, z, def.rt.id, state); + if (lighting) { + lighting->onBlockSet(x, y, z, def.rt.id); + } scripting::on_block_placed(player, def, glm::ivec3(x, y, z)); if (def.rt.extended) { updateSides(x, y, z , def.size.x, def.size.y, def.size.z); @@ -96,12 +105,12 @@ void BlocksController::placeBlock( } void BlocksController::updateBlock(int x, int y, int z) { - voxel* vox = chunks.get(x, y, z); + voxel* vox = blocks_agent::get(chunks, x, y, z); if (vox == nullptr) return; const auto& def = level.content->getIndices()->blocks.require(vox->id); if (def.grounded) { const auto& vec = get_ground_direction(def, vox->state.rotation); - if (!chunks.isSolidBlock(x + vec.x, y + vec.y, z + vec.z)) { + if (!blocks_agent::is_solid_at(chunks, x + vec.x, y + vec.y, z + vec.z)) { breakBlock(nullptr, def, x, y, z); return; } @@ -162,28 +171,48 @@ void BlocksController::randomTick( void BlocksController::randomTick(int tickid, int parts) { auto indices = level.content->getIndices(); - int width = chunks.getWidth(); - int height = chunks.getHeight(); - int segments = 4; - for (uint z = padding; z < height - padding; z++) { - for (uint x = padding; x < width - padding; x++) { - int index = z * width + x; - if ((index + tickid) % parts != 0) { - continue; + std::set chunksIterated; + + for (const auto& [pid, player] : *level.players) { + const auto& chunks = *player->chunks; + int offsetX = chunks.getOffsetX(); + int offsetY = chunks.getOffsetY(); + int width = chunks.getWidth(); + int height = chunks.getHeight(); + int segments = 4; + + for (uint z = padding; z < height - padding; z++) { + for (uint x = padding; x < width - padding; x++) { + int index = z * width + x; + if ((index + tickid) % parts != 0) { + continue; + } + auto& chunk = chunks.getChunks()[index]; + if (chunk == nullptr || !chunk->flags.lighted) { + continue; + } + union { + int32_t pos[2]; + uint64_t key; + } posU; + posU.pos[0] = x + offsetX; + posU.pos[1] = z + offsetY; + if (chunksIterated.find(posU.key) != chunksIterated.end()) { + continue; + } + chunksIterated.insert(posU.key); + randomTick(*chunk, segments, indices); } - auto& chunk = chunks.getChunks()[index]; - if (chunk == nullptr || !chunk->flags.lighted) { - continue; - } - randomTick(*chunk, segments, indices); } } } int64_t BlocksController::createBlockInventory(int x, int y, int z) { - auto chunk = chunks.getChunkByVoxel(x, y, z); - if (chunk == nullptr) { + auto chunk = blocks_agent::get_chunk( + chunks, floordiv(x), floordiv(z) + ); + if (chunk == nullptr || y < 0 || y >= CHUNK_H) { return 0; } int lx = x - chunk->x * CHUNK_W; @@ -203,7 +232,9 @@ int64_t BlocksController::createBlockInventory(int x, int y, int z) { } void BlocksController::bindInventory(int64_t invid, int x, int y, int z) { - auto chunk = chunks.getChunkByVoxel(x, y, z); + auto chunk = blocks_agent::get_chunk( + chunks, floordiv(x), floordiv(z) + ); if (chunk == nullptr) { throw std::runtime_error("block does not exists"); } @@ -216,7 +247,9 @@ void BlocksController::bindInventory(int64_t invid, int x, int y, int z) { } void BlocksController::unbindInventory(int x, int y, int z) { - auto chunk = chunks.getChunkByVoxel(x, y, z); + auto chunk = blocks_agent::get_chunk( + chunks, floordiv(x), floordiv(z) + ); if (chunk == nullptr) { throw std::runtime_error("block does not exists"); } diff --git a/src/logic/BlocksController.hpp b/src/logic/BlocksController.hpp index a8f286dc..1dd48983 100644 --- a/src/logic/BlocksController.hpp +++ b/src/logic/BlocksController.hpp @@ -14,19 +14,20 @@ class Level; class Chunk; class Chunks; class Lighting; +class GlobalChunks; class ContentIndices; enum class BlockInteraction { step, destruction, placing }; /// @brief Player argument is nullable using on_block_interaction = std::function< - void(Player*, const glm::ivec3&, const Block&, BlockInteraction type)>; + void(Player*, const glm::ivec3&, const Block&, BlockInteraction)>; /// BlocksController manages block updates and data (inventories, metadata) class BlocksController { const Level& level; - Chunks& chunks; - Lighting& lighting; + GlobalChunks& chunks; + Lighting* lighting; util::Clock randTickClock; util::Clock blocksTickClock; util::Clock worldTickClock; @@ -34,7 +35,7 @@ class BlocksController { FastRandom random {}; std::vector blockInteractionCallbacks; public: - BlocksController(const Level& level, Lighting& lighting, uint padding); + BlocksController(const Level& level, Lighting* lighting, uint padding); void updateSides(int x, int y, int z); void updateSides(int x, int y, int z, int w, int h, int d); diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index 55ab262d..13c7ab86 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -11,6 +11,7 @@ #include "lighting/Lighting.hpp" #include "maths/voxmaths.hpp" #include "util/timeutil.hpp" +#include "objects/Player.hpp" #include "voxels/Block.hpp" #include "voxels/Chunk.hpp" #include "voxels/Chunks.hpp" @@ -24,8 +25,6 @@ const uint MIN_SURROUNDING = 9; ChunksController::ChunksController(Level& level, uint padding) : level(level), - chunks(*level.chunks), - lighting(std::make_unique(level.content, level.chunks.get())), padding(padding), generator(std::make_unique( level.content->generators.require(level.getWorld()->getGenerator()), @@ -36,15 +35,19 @@ ChunksController::ChunksController(Level& level, uint padding) ChunksController::~ChunksController() = default; void ChunksController::update( - int64_t maxDuration, int loadDistance, int centerX, int centerY -) { + int64_t maxDuration, int loadDistance, Player& player +) const { + const auto& position = player.getPosition(); + int centerX = floordiv(position.x); + int centerY = floordiv(position.z); + generator->update(centerX, centerY, loadDistance); int64_t mcstotal = 0; for (uint i = 0; i < MAX_WORK_PER_FRAME; i++) { timeutil::Timer timer; - if (loadVisible()) { + if (loadVisible(player)) { int64_t mcs = timer.stop(); if (mcstotal + mcs < maxDuration * 1000) { mcstotal += mcs; @@ -55,7 +58,8 @@ void ChunksController::update( } } -bool ChunksController::loadVisible() { +bool ChunksController::loadVisible(const Player& player) const { + const auto& chunks = *player.chunks; int sizeX = chunks.getWidth(); int sizeY = chunks.getHeight(); @@ -69,7 +73,7 @@ bool ChunksController::loadVisible() { auto& chunk = chunks.getChunks()[index]; if (chunk != nullptr) { if (chunk->flags.loaded && !chunk->flags.lighted) { - if (buildLights(chunk)) { + if (buildLights(player, chunk)) { return true; } } @@ -93,32 +97,35 @@ bool ChunksController::loadVisible() { } int offsetX = chunks.getOffsetX(); int offsetY = chunks.getOffsetY(); - createChunk(nearX + offsetX, nearZ + offsetY); + createChunk(player, nearX + offsetX, nearZ + offsetY); return true; } -bool ChunksController::buildLights(const std::shared_ptr& chunk) { +bool ChunksController::buildLights(const Player& player, const std::shared_ptr& chunk) const { int surrounding = 0; for (int oz = -1; oz <= 1; oz++) { for (int ox = -1; ox <= 1; ox++) { - if (chunks.getChunk(chunk->x + ox, chunk->z + oz)) surrounding++; + if (player.chunks->getChunk(chunk->x + ox, chunk->z + oz)) + surrounding++; } } if (surrounding == MIN_SURROUNDING) { - bool lightsCache = chunk->flags.loadedLights; - if (!lightsCache) { - lighting->buildSkyLight(chunk->x, chunk->z); + if (lighting) { + bool lightsCache = chunk->flags.loadedLights; + if (!lightsCache) { + lighting->buildSkyLight(chunk->x, chunk->z); + } + lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); } - lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); chunk->flags.lighted = true; return true; } return false; } -void ChunksController::createChunk(int x, int z) { +void ChunksController::createChunk(const Player& player, int x, int z) const { auto chunk = level.chunksStorage->create(x, z); - chunks.putChunk(chunk); + player.chunks->putChunk(chunk); auto& chunkFlags = chunk->flags; if (!chunkFlags.loaded) { diff --git a/src/logic/ChunksController.hpp b/src/logic/ChunksController.hpp index 71dada6f..6272fd01 100644 --- a/src/logic/ChunksController.hpp +++ b/src/logic/ChunksController.hpp @@ -7,6 +7,7 @@ class Level; class Chunk; class Chunks; +class Player; class Lighting; class WorldGenerator; @@ -14,14 +15,13 @@ class WorldGenerator; class ChunksController { private: Level& level; - Chunks& chunks; uint padding; std::unique_ptr generator; /// @brief Process one chunk: load it or calculate lights for it - bool loadVisible(); - bool buildLights(const std::shared_ptr& chunk); - void createChunk(int x, int y); + bool loadVisible(const Player& player) const; + bool buildLights(const Player& player, const std::shared_ptr& chunk) const; + void createChunk(const Player& player, int x, int y) const; public: std::unique_ptr lighting; @@ -29,11 +29,7 @@ public: ~ChunksController(); /// @param maxDuration milliseconds reserved for chunks loading - void update( - int64_t maxDuration, - int loadDistance, - int centerX, - int centerY); + void update(int64_t maxDuration, int loadDistance, Player& player) const; const WorldGenerator* getGenerator() const { return generator.get(); diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 2f363dad..409a81b4 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -10,21 +10,33 @@ #include "objects/Players.hpp" #include "objects/Player.hpp" #include "physics/Hitbox.hpp" +#include "voxels/Chunks.hpp" #include "scripting/scripting.hpp" +#include "lighting/Lighting.hpp" #include "settings.hpp" #include "world/Level.hpp" #include "world/World.hpp" static debug::Logger logger("level-control"); -LevelController::LevelController(Engine* engine, std::unique_ptr levelPtr) +LevelController::LevelController( + Engine* engine, std::unique_ptr levelPtr, Player* clientPlayer +) : settings(engine->getSettings()), level(std::move(levelPtr)), chunks(std::make_unique( *level, settings.chunks.padding.get() )) { + + if (clientPlayer) { + chunks->lighting = std::make_unique( + level->content, clientPlayer->chunks.get() + ); + } blocks = std::make_unique( - *level, *chunks->lighting, settings.chunks.padding.get() + *level, + chunks ? chunks->lighting.get() : nullptr, + settings.chunks.padding.get() ); scripting::on_world_load(this); } @@ -32,14 +44,15 @@ LevelController::LevelController(Engine* engine, std::unique_ptr levelPtr void LevelController::update(float delta, bool pause) { for (const auto& [uid, player] : *level->players) { glm::vec3 position = player->getPosition(); - level->loadMatrix( + player->chunks->configure( position.x, position.z, - settings.chunks.loadDistance.get() + settings.chunks.padding.get() * 2 + settings.chunks.loadDistance.get() + settings.chunks.padding.get() ); chunks->update( - settings.chunks.loadSpeed.get(), settings.chunks.loadDistance.get(), - floordiv(position.x, CHUNK_W), floordiv(position.z, CHUNK_D) + settings.chunks.loadSpeed.get(), + settings.chunks.loadDistance.get(), + *player ); } if (!pause) { diff --git a/src/logic/LevelController.hpp b/src/logic/LevelController.hpp index 6cfcf816..5363976b 100644 --- a/src/logic/LevelController.hpp +++ b/src/logic/LevelController.hpp @@ -18,7 +18,7 @@ class LevelController { std::unique_ptr blocks; std::unique_ptr chunks; public: - LevelController(Engine* engine, std::unique_ptr level); + LevelController(Engine* engine, std::unique_ptr level, Player* clientPlayer); /// @param delta time elapsed since the last update /// @param pause is world and player simulation paused diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 827b42c1..6159a389 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -215,7 +215,7 @@ void PlayerController::onFootstep(const Hitbox& hitbox) { int x = std::floor(pos.x + half.x * offsetX); int y = std::floor(pos.y - half.y * 1.1f); int z = std::floor(pos.z + half.z * offsetZ); - auto vox = level->chunks->get(x, y, z); + auto vox = player->chunks->get(x, y, z); if (vox) { auto& def = level->content->getIndices()->blocks.require(vox->id); if (!def.obstacle) { @@ -274,7 +274,7 @@ void PlayerController::postUpdate(float delta, bool input, bool pause) { camControl.updateMouse(this->input); } player->postUpdate(); - camControl.update(this->input, pause ? 0.0f : delta, level->chunks.get()); + camControl.update(this->input, pause ? 0.0f : delta, player->chunks.get()); if (input) { updateInteraction(delta); } else { @@ -366,14 +366,14 @@ static void pick_block( voxel* PlayerController::updateSelection(float maxDistance) { auto indices = level->content->getIndices(); - auto chunks = level->chunks.get(); + auto& chunks = *player->chunks; auto camera = player->fpCamera.get(); auto& selection = player->selection; glm::vec3 end; glm::ivec3 iend; glm::ivec3 norm; - voxel* vox = chunks->rayCast( + voxel* vox = chunks.rayCast( camera->position, camera->front, maxDistance, end, norm, iend ); if (vox) { @@ -411,12 +411,12 @@ voxel* PlayerController::updateSelection(float maxDistance) { blockstate selectedState = vox->state; selection.vox = *vox; if (selectedState.segment) { - selection.position = chunks->seekOrigin( + selection.position = chunks.seekOrigin( iend, indices->blocks.require(selection.vox.id), selectedState ); - auto origin = chunks->get(selection.position); + auto origin = chunks.get(selection.position); if (origin && origin->id != vox->id) { - chunks->set(iend.x, iend.y, iend.z, 0, {}); + chunks.set(iend.x, iend.y, iend.z, 0, {}); return updateSelection(maxDistance); } } else { @@ -429,7 +429,7 @@ voxel* PlayerController::updateSelection(float maxDistance) { void PlayerController::processRightClick(const Block& def, const Block& target) { const auto& selection = player->selection; - auto chunks = level->chunks.get(); + auto& chunks = *player->chunks; auto camera = player->fpCamera.get(); blockstate state {}; @@ -458,16 +458,16 @@ void PlayerController::processRightClick(const Block& def, const Block& target) } } } - auto vox = chunks->get(coord); + auto vox = chunks.get(coord); if (vox == nullptr) { return; } - if (!chunks->checkReplaceability(def, state, coord)) { + if (!chunks.checkReplaceability(def, state, coord)) { return; } if (def.grounded) { const auto& vec = get_ground_direction(def, state.rotation); - if (!chunks->isSolidBlock( + if (!chunks.isSolidBlock( coord.x + vec.x, coord.y + vec.y, coord.z + vec.z )) { return; @@ -502,7 +502,7 @@ void PlayerController::updateEntityInteraction( void PlayerController::updateInteraction(float delta) { auto indices = level->content->getIndices(); - auto chunks = level->chunks.get(); + auto chunks = player->chunks.get(); const auto& selection = player->selection; if (interactionTimer > 0.0f) { diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index 24b00124..180a959f 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -40,7 +40,9 @@ static int l_is_solid_at(lua::State* L) { auto x = lua::tointeger(L, 1); auto y = lua::tointeger(L, 2); auto z = lua::tointeger(L, 3); - return lua::pushboolean(L, blocks_agent::is_solid_at(*level->chunks, x, y, z)); + return lua::pushboolean( + L, blocks_agent::is_solid_at(*level->chunksStorage, x, y, z) + ); } static int l_count(lua::State* L) { diff --git a/src/logic/scripting/lua/libs/libentity.cpp b/src/logic/scripting/lua/libs/libentity.cpp index ba3bd349..bf547f95 100644 --- a/src/logic/scripting/lua/libs/libentity.cpp +++ b/src/logic/scripting/lua/libs/libentity.cpp @@ -9,6 +9,7 @@ #include "physics/Hitbox.hpp" #include "voxels/Chunks.hpp" #include "voxels/Block.hpp" +#include "voxels/blocks_agent.hpp" #include "window/Camera.hpp" using namespace scripting; @@ -149,8 +150,15 @@ static int l_raycast(lua::State* L) { blockid_t block = BLOCK_VOID; - if (auto voxel = level->chunks->rayCast( - start, dir, maxDistance, end, normal, iend, filteredBlocks + if (auto voxel = blocks_agent::raycast( + *level->chunksStorage, + start, + dir, + maxDistance, + end, + normal, + iend, + filteredBlocks )) { maxDistance = glm::distance(start, end); block = voxel->id; diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 034f6597..00d767c2 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -28,7 +28,7 @@ static int l_create_fragment(lua::State* L) { bool saveEntities = lua::toboolean(L, 4); auto fragment = - VoxelFragment::create(level, pointA, pointB, crop, saveEntities); + VoxelFragment::create(*level, pointA, pointB, crop, saveEntities); return lua::newuserdata( L, std::shared_ptr(std::move(fragment)) ); diff --git a/src/logic/scripting/lua/libs/libhud.cpp b/src/logic/scripting/lua/libs/libhud.cpp index 7f5ec46d..f12ba0a7 100644 --- a/src/logic/scripting/lua/libs/libhud.cpp +++ b/src/logic/scripting/lua/libs/libhud.cpp @@ -14,6 +14,7 @@ #include "voxels/Block.hpp" #include "voxels/Chunks.hpp" #include "voxels/voxel.hpp" +#include "voxels/blocks_agent.hpp" #include "world/Level.hpp" #include "api_lua.hpp" @@ -59,7 +60,7 @@ static int l_open_block(lua::State* L) { auto z = lua::tointeger(L, 3); bool playerInventory = !lua::toboolean(L, 4); - auto vox = level->chunks->get(x, y, z); + auto vox = blocks_agent::get(*level->chunksStorage, x, y, z); if (vox == nullptr) { throw std::runtime_error( "block does not exists at " + std::to_string(x) + " " + diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 58e2bdc4..16e81d56 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -125,7 +125,7 @@ static int l_get_generator(lua::State* L) { static int l_get_chunk_data(lua::State* L) { int x = (int)lua::tointeger(L, 1); int y = (int)lua::tointeger(L, 2); - const auto& chunk = level->chunks->getChunk(x, y); + const auto& chunk = level->chunksStorage->getChunk(x, y); if (chunk == nullptr) { lua::pushnil(L); return 0; @@ -181,8 +181,8 @@ static int l_set_chunk_data(lua::State* L) { if (lua::gettop(L) >= 4) { is_compressed = lua::toboolean(L, 4); } - auto chunk = level->chunks->getChunk(x, y); - if(chunk== nullptr){ + auto chunk = level->chunksStorage->getChunk(x, y); + if (chunk == nullptr) { return 0; } if (is_compressed) { @@ -217,22 +217,22 @@ static int l_set_chunk_data(lua::State* L) { chunk->flags.modified = true; lighting.onChunkLoaded(x, y, true); - chunk = level->chunks->getChunk(x - 1, y); + chunk = level->chunksStorage->getChunk(x - 1, y); if (chunk != nullptr) { chunk->flags.modified = true; lighting.onChunkLoaded(x - 1, y, true); } - chunk = level->chunks->getChunk(x + 1, y); + chunk = level->chunksStorage->getChunk(x + 1, y); if (chunk != nullptr) { chunk->flags.modified = true; lighting.onChunkLoaded(x + 1, y, true); } - chunk = level->chunks->getChunk(x, y - 1); + chunk = level->chunksStorage->getChunk(x, y - 1); if (chunk != nullptr) { chunk->flags.modified = true; lighting.onChunkLoaded(x, y - 1, true); } - chunk = level->chunks->getChunk(x, y + 1); + chunk = level->chunksStorage->getChunk(x, y + 1); if (chunk != nullptr) { chunk->flags.modified = true; lighting.onChunkLoaded(x, y + 1, true); diff --git a/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp b/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp index f123be6f..4a7af971 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp @@ -26,7 +26,7 @@ static int l_place(lua::State* L) { auto offset = tovec3(L, 2); int rotation = tointeger(L, 3) & 0b11; fragment->getFragment()->place( - *scripting::level->chunks, offset, rotation + *scripting::level->chunksStorage, offset, rotation ); } return 0; diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index 79c0ba66..d2e5742d 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -459,7 +459,7 @@ void Entities::updatePhysics(float delta) { float vel = glm::length(prevVel); int substeps = static_cast(delta * vel * 20); substeps = std::min(100, std::max(2, substeps)); - physics->step(level->chunks.get(), &hitbox, delta, substeps, eid.uid); + physics->step(*level->chunksStorage, &hitbox, delta, substeps, eid.uid); hitbox.linearDamping = hitbox.grounded * 24; transform.setPos(hitbox.position); if (hitbox.grounded && !grounded) { diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index 0dd58f91..0a2106ed 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -205,12 +205,12 @@ void Player::attemptToFindSpawnpoint() { position.z + (rand() % 200 - 100) ); while (newpos.y > 0 && - !level->chunks->isObstacleBlock(newpos.x, newpos.y - 2, newpos.z)) { + !chunks->isObstacleBlock(newpos.x, newpos.y - 2, newpos.z)) { newpos.y--; } - voxel* headvox = level->chunks->get(newpos.x, newpos.y + 1, newpos.z); - if (level->chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) || + voxel* headvox = chunks->get(newpos.x, newpos.y + 1, newpos.z); + if (chunks->isObstacleBlock(newpos.x, newpos.y, newpos.z) || headvox == nullptr || headvox->id != 0) { return; } diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index 95954380..5f7824a1 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -3,7 +3,7 @@ #include "maths/aabb.hpp" #include "voxels/Block.hpp" -#include "voxels/Chunks.hpp" +#include "voxels/GlobalChunks.hpp" #include "voxels/voxel.hpp" #include @@ -18,7 +18,7 @@ PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) { } void PhysicsSolver::step( - Chunks* chunks, + const GlobalChunks& chunks, Hitbox* hitbox, float delta, uint substeps, @@ -63,7 +63,7 @@ void PhysicsSolver::step( float x = (px-half.x+E) + ix * s; for (int iz = 0; iz <= (half.z-E)*2/s; iz++){ float z = (pos.z-half.z+E) + iz * s; - if (chunks->isObstacleAt(x,y,z)){ + if (chunks.isObstacleAt(x,y,z)){ hitbox->grounded = true; break; } @@ -77,7 +77,7 @@ void PhysicsSolver::step( float x = (pos.x-half.x+E) + ix * s; for (int iz = 0; iz <= (half.z-E)*2/s; iz++){ float z = (pz-half.z+E) + iz * s; - if (chunks->isObstacleAt(x,y,z)){ + if (chunks.isObstacleAt(x,y,z)){ hitbox->grounded = true; break; } @@ -119,8 +119,8 @@ void PhysicsSolver::step( } static float calc_step_height( - Chunks* chunks, - glm::vec3& pos, + const GlobalChunks& chunks, + const glm::vec3& pos, const glm::vec3& half, float stepHeight, float s @@ -130,7 +130,7 @@ static float calc_step_height( float x = (pos.x-half.x+E) + ix * s; for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { float z = (pos.z-half.z+E) + iz * s; - if (chunks->isObstacleAt(x, pos.y+half.y+stepHeight, z)) { + if (chunks.isObstacleAt(x, pos.y+half.y+stepHeight, z)) { return 0.0f; } } @@ -141,7 +141,7 @@ static float calc_step_height( template static bool calc_collision_neg( - Chunks* chunks, + const GlobalChunks& chunks, glm::vec3& pos, glm::vec3& vel, const glm::vec3& half, @@ -159,7 +159,7 @@ static bool calc_collision_neg( coord[nz] = (pos[nz]-half[nz]+E) + iz * s; coord[nx] = (pos[nx]-half[nx]-E); - if (const auto aabb = chunks->isObstacleAt(coord.x, coord.y, coord.z)) { + if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z)) { vel[nx] = 0.0f; float newx = std::floor(coord[nx]) + aabb->max()[nx] + half[nx] + E; if (std::abs(newx-pos[nx]) <= MAX_FIX) { @@ -174,7 +174,7 @@ static bool calc_collision_neg( template static void calc_collision_pos( - Chunks* chunks, + const GlobalChunks& chunks, glm::vec3& pos, glm::vec3& vel, const glm::vec3& half, @@ -191,7 +191,7 @@ static void calc_collision_pos( for (int iz = 0; iz <= (half[nz]-E)*2/s; iz++) { coord[nz] = (pos[nz]-half[nz]+E) + iz * s; coord[nx] = (pos[nx]+half[nx]+E); - if (const auto aabb = chunks->isObstacleAt(coord.x, coord.y, coord.z)) { + if (const auto aabb = chunks.isObstacleAt(coord.x, coord.y, coord.z)) { vel[nx] = 0.0f; float newx = std::floor(coord[nx]) - half[nx] + aabb->min()[nx] - E; if (std::abs(newx-pos[nx]) <= MAX_FIX) { @@ -204,7 +204,7 @@ static void calc_collision_pos( } void PhysicsSolver::colisionCalc( - Chunks* chunks, + const GlobalChunks& chunks, Hitbox* hitbox, glm::vec3& vel, glm::vec3& pos, @@ -234,7 +234,7 @@ void PhysicsSolver::colisionCalc( for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { float z = (pos.z-half.z+E) + iz * s; float y = (pos.y-half.y+E); - if ((aabb = chunks->isObstacleAt(x,y,z))){ + if ((aabb = chunks.isObstacleAt(x,y,z))){ vel.y = 0.0f; float newy = std::floor(y) + aabb->max().y + half.y; if (std::abs(newy-pos.y) <= MAX_FIX+stepHeight) { @@ -251,7 +251,7 @@ void PhysicsSolver::colisionCalc( for (int iz = 0; iz <= (half.z-E)*2/s; iz++) { float z = (pos.z-half.z+E) + iz * s; float y = (pos.y+half.y+E); - if ((aabb = chunks->isObstacleAt(x,y,z))){ + if ((aabb = chunks.isObstacleAt(x,y,z))){ vel.y = 0.0f; float newy = std::floor(y) - half.y + aabb->min().y - E; if (std::abs(newy-pos.y) <= MAX_FIX) { diff --git a/src/physics/PhysicsSolver.hpp b/src/physics/PhysicsSolver.hpp index 35f8158e..5fa154fc 100644 --- a/src/physics/PhysicsSolver.hpp +++ b/src/physics/PhysicsSolver.hpp @@ -9,7 +9,7 @@ #include class Block; -class Chunks; +class GlobalChunks; struct Sensor; class PhysicsSolver { @@ -18,14 +18,14 @@ class PhysicsSolver { public: PhysicsSolver(glm::vec3 gravity); void step( - Chunks* chunks, + const GlobalChunks& chunks, Hitbox* hitbox, float delta, uint substeps, entityid_t entity ); void colisionCalc( - Chunks* chunks, + const GlobalChunks& chunks, Hitbox* hitbox, glm::vec3& vel, glm::vec3& pos, diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 91b05d69..37eae563 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -38,6 +38,14 @@ Chunks::Chunks( }); } +void Chunks::configure(int32_t x, int32_t z, uint32_t radius) { + setCenter(x, z); + uint32_t diameter = radius * 2LL; + if (getWidth() != diameter) { + resize(diameter, diameter); + } +} + voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const { return blocks_agent::get(*this, x, y, z); } diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index c1c75e9c..86e02255 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -50,6 +50,8 @@ public: ); ~Chunks() = default; + void configure(int32_t x, int32_t z, uint32_t radius); + bool putChunk(const std::shared_ptr& chunk); Chunk* getChunk(int32_t x, int32_t z) const; diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 98a2d40a..a85be528 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -10,6 +10,7 @@ #include "lighting/Lightmap.hpp" #include "maths/voxmaths.hpp" #include "objects/Entities.hpp" +#include "voxels/blocks_agent.hpp" #include "typedefs.hpp" #include "world/Level.hpp" #include "world/World.hpp" @@ -198,3 +199,7 @@ void GlobalChunks::saveAll() { void GlobalChunks::putChunk(std::shared_ptr chunk) { chunksMap[keyfrom(chunk->x, chunk->z)] = std::move(chunk); } + +const AABB* GlobalChunks::isObstacleAt(float x, float y, float z) const { + return blocks_agent::is_obstacle_at(*this, x, y, z); +} diff --git a/src/voxels/GlobalChunks.hpp b/src/voxels/GlobalChunks.hpp index afbdf67c..b4bb45e9 100644 --- a/src/voxels/GlobalChunks.hpp +++ b/src/voxels/GlobalChunks.hpp @@ -11,6 +11,7 @@ class Chunk; class Level; +struct AABB; class ContentIndices; class GlobalChunks { @@ -51,6 +52,8 @@ public: void putChunk(std::shared_ptr chunk); + const AABB* isObstacleAt(float x, float y, float z) const; + inline Chunk* getChunk(int cx, int cz) const { const auto& found = chunksMap.find(keyfrom(cx, cz)); if (found == chunksMap.end()) { diff --git a/src/voxels/blocks_agent.cpp b/src/voxels/blocks_agent.cpp index ab39ea29..a23fa9ef 100644 --- a/src/voxels/blocks_agent.cpp +++ b/src/voxels/blocks_agent.cpp @@ -265,3 +265,105 @@ voxel* blocks_agent::raycast( ) { return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter); } + +// reduce nesting on next modification +// 25.06.2024: not now +// 11.11.2024: not now +template +inline void get_voxels_impl( + const Storage& chunks, VoxelsVolume* volume, bool backlight +) { + const auto& blocks = chunks.getContentIndices().blocks; + voxel* voxels = volume->getVoxels(); + light_t* lights = volume->getLights(); + int x = volume->getX(); + int y = volume->getY(); + int z = volume->getZ(); + + int w = volume->getW(); + int h = volume->getH(); + int d = volume->getD(); + + int scx = floordiv(x); + int scz = floordiv(z); + + int ecx = floordiv(x + w); + int ecz = floordiv(z + d); + + int cw = ecx - scx + 1; + int cd = ecz - scz + 1; + + // cw*cd chunks will be scanned + for (int cz = scz; cz < scz + cd; cz++) { + for (int cx = scx; cx < scx + cw; cx++) { + const auto chunk = get_chunk(chunks, cx, cz); + if (chunk == nullptr) { + // no chunk loaded -> filling with BLOCK_VOID + for (int ly = y; ly < y + h; ly++) { + for (int lz = std::max(z, cz * CHUNK_D); + lz < std::min(z + d, (cz + 1) * CHUNK_D); + lz++) { + for (int lx = std::max(x, cx * CHUNK_W); + lx < std::min(x + w, (cx + 1) * CHUNK_W); + lx++) { + uint idx = vox_index(lx - x, ly - y, lz - z, w, d); + voxels[idx].id = BLOCK_VOID; + lights[idx] = 0; + } + } + } + } else { + const voxel* cvoxels = chunk->voxels; + const light_t* clights = chunk->lightmap.getLights(); + for (int ly = y; ly < y + h; ly++) { + for (int lz = std::max(z, cz * CHUNK_D); + lz < std::min(z + d, (cz + 1) * CHUNK_D); + lz++) { + for (int lx = std::max(x, cx * CHUNK_W); + lx < std::min(x + w, (cx + 1) * CHUNK_W); + lx++) { + uint vidx = vox_index(lx - x, ly - y, lz - z, w, d); + uint cidx = vox_index( + lx - cx * CHUNK_W, + ly, + lz - cz * CHUNK_D, + CHUNK_W, + CHUNK_D + ); + voxels[vidx] = cvoxels[cidx]; + light_t light = clights[cidx]; + if (backlight) { + const auto block = blocks.get(voxels[vidx].id); + if (block && block->lightPassing) { + light = Lightmap::combine( + std::min(15, + Lightmap::extract(light, 0) + 1), + std::min(15, + Lightmap::extract(light, 1) + 1), + std::min(15, + Lightmap::extract(light, 2) + 1), + std::min(15, + static_cast(Lightmap::extract(light, 3))) + ); + } + } + lights[vidx] = light; + } + } + } + } + } + } +} + +void blocks_agent::get_voxels( + const Chunks& chunks, VoxelsVolume* volume, bool backlight +) { + get_voxels_impl(chunks, volume, backlight); +} + +void blocks_agent::get_voxels( + const GlobalChunks& chunks, VoxelsVolume* volume, bool backlight +) { + get_voxels_impl(chunks, volume, backlight); +} diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index e2c4266e..72cdd5ab 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -6,6 +6,7 @@ #include "Block.hpp" #include "Chunk.hpp" #include "Chunks.hpp" +#include "VoxelsVolume.hpp" #include "GlobalChunks.hpp" #include "constants.hpp" #include "typedefs.hpp" @@ -17,6 +18,8 @@ #include #include +struct AABB; + namespace blocks_agent { /// @brief Get specified chunk. @@ -432,4 +435,42 @@ voxel* raycast( std::set filter ); +void get_voxels(const Chunks& chunks, VoxelsVolume* volume, bool backlight=false); + +void get_voxels(const GlobalChunks& chunks, VoxelsVolume* volume, bool backlight=false); + +template +inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float z) { + int ix = std::floor(x); + int iy = std::floor(y); + int iz = std::floor(z); + voxel* v = get(chunks, ix, iy, iz); + if (v == nullptr) { + if (iy >= CHUNK_H) { + return nullptr; + } else { + static const AABB empty; + return ∅ + } + } + const auto& def = chunks.getContentIndices().blocks.require(v->id); + if (def.obstacle) { + glm::ivec3 offset {}; + if (v->state.segment) { + glm::ivec3 point(ix, iy, iz); + offset = seek_origin(chunks, point, def, v->state) - point; + } + const auto& boxes = + def.rotatable ? def.rt.hitboxes[v->state.rotation] : def.hitboxes; + for (const auto& hitbox : boxes) { + if (hitbox.contains( + {x - ix - offset.x, y - iy - offset.y, z - iz - offset.z} + )) { + return &hitbox; + } + } + } + return nullptr; +} + } // blocks_agent diff --git a/src/world/Level.cpp b/src/world/Level.cpp index c289579f..3625f62e 100644 --- a/src/world/Level.cpp +++ b/src/world/Level.cpp @@ -4,7 +4,6 @@ #include "data/dv_util.hpp" #include "items/Inventories.hpp" #include "items/Inventory.hpp" -#include "lighting/Lighting.hpp" #include "objects/Entities.hpp" #include "objects/Player.hpp" #include "objects/Players.hpp" @@ -12,7 +11,6 @@ #include "physics/PhysicsSolver.hpp" #include "settings.hpp" #include "voxels/Chunk.hpp" -#include "voxels/Chunks.hpp" #include "voxels/GlobalChunks.hpp" #include "window/Camera.hpp" #include "LevelEvents.hpp" @@ -60,31 +58,11 @@ Level::Level( events->listen(LevelEventType::EVT_CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) { chunksStorage->decref(chunk); }); - - uint matrixSize = - (settings.chunks.loadDistance.get() + settings.chunks.padding.get()) * - 2; - chunks = std::make_unique( - matrixSize, matrixSize, 0, 0, events.get(), content->getIndices() - ); - inventories = std::make_unique(*this); } Level::~Level() = default; -void Level::loadMatrix(int32_t x, int32_t z, uint32_t radius) { - chunks->setCenter(x, z); - uint32_t diameter = std::min( - radius * 2LL, - (settings.chunks.loadDistance.get() + settings.chunks.padding.get()) * - 2LL - ); - if (chunks->getWidth() != diameter) { - chunks->resize(diameter, diameter); - } -} - World* Level::getWorld() { return world.get(); } diff --git a/src/world/Level.hpp b/src/world/Level.hpp index b30bde3b..9994c01d 100644 --- a/src/world/Level.hpp +++ b/src/world/Level.hpp @@ -9,11 +9,9 @@ class Content; class World; -class Chunks; class Entities; class Inventories; class LevelEvents; -class Lighting; class PhysicsSolver; class GlobalChunks; class Camera; @@ -27,7 +25,6 @@ class Level { public: const Content* const content; - std::unique_ptr chunks; std::unique_ptr chunksStorage; std::unique_ptr inventories; @@ -44,8 +41,6 @@ public: ); ~Level(); - void loadMatrix(int32_t x, int32_t z, uint32_t radius); - World* getWorld(); const World* getWorld() const; diff --git a/src/world/generator/VoxelFragment.cpp b/src/world/generator/VoxelFragment.cpp index 2d7ab923..af92dc7e 100644 --- a/src/world/generator/VoxelFragment.cpp +++ b/src/world/generator/VoxelFragment.cpp @@ -10,11 +10,12 @@ #include "voxels/Block.hpp" #include "voxels/GlobalChunks.hpp" #include "voxels/VoxelsVolume.hpp" +#include "voxels/blocks_agent.hpp" #include "world/Level.hpp" #include "core_defs.hpp" std::unique_ptr VoxelFragment::create( - Level* level, + const Level& level, const glm::ivec3& a, const glm::ivec3& b, bool crop, @@ -26,7 +27,7 @@ std::unique_ptr VoxelFragment::create( if (crop) { VoxelsVolume volume(size.x, size.y, size.z); volume.setPosition(start.x, start.y, start.z); - level->chunks->getVoxels(&volume); + blocks_agent::get_voxels(*level.chunksStorage, &volume); auto end = start + size; @@ -51,14 +52,14 @@ std::unique_ptr VoxelFragment::create( VoxelsVolume volume(size.x, size.y, size.z); volume.setPosition(start.x, start.y, start.z); - level->chunks->getVoxels(&volume); + blocks_agent::get_voxels(*level.chunksStorage, &volume); auto volVoxels = volume.getVoxels(); std::vector voxels(size.x * size.y * size.z); std::vector blockNames {CORE_AIR}; std::unordered_map blocksRegistered {{0, 0}}; - auto contentIndices = level->content->getIndices(); + auto contentIndices = level.content->getIndices(); for (size_t i = 0 ; i < voxels.size(); i++) { blockid_t id = volVoxels[i].id; blockid_t index; @@ -170,7 +171,7 @@ void VoxelFragment::prepare(const Content& content) { } void VoxelFragment::place( - Chunks& chunks, const glm::ivec3& offset, ubyte rotation + GlobalChunks& chunks, const glm::ivec3& offset, ubyte rotation ) { auto& structVoxels = getRuntimeVoxels(); for (int y = 0; y < size.y; y++) { @@ -185,7 +186,9 @@ void VoxelFragment::place( const auto& structVoxel = structVoxels[vox_index(x, y, z, size.x, size.z)]; if (structVoxel.id) { - chunks.set(sx, sy, sz, structVoxel.id, structVoxel.state); + blocks_agent::set( + chunks, sx, sy, sz, structVoxel.id, structVoxel.state + ); } } } diff --git a/src/world/generator/VoxelFragment.hpp b/src/world/generator/VoxelFragment.hpp index 701cac0e..6efa1998 100644 --- a/src/world/generator/VoxelFragment.hpp +++ b/src/world/generator/VoxelFragment.hpp @@ -10,7 +10,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1; class Level; class Content; -class Chunks; +class GlobalChunks; class VoxelFragment : public Serializable { glm::ivec3 size; @@ -45,13 +45,13 @@ public: /// @brief Place fragment to the world /// @param offset target location /// @param rotation rotation index - void place(Chunks& chunks, const glm::ivec3& offset, ubyte rotation); + void place(GlobalChunks& chunks, const glm::ivec3& offset, ubyte rotation); /// @brief Create structure copy rotated 90 deg. clockwise std::unique_ptr rotated(const Content& content) const; static std::unique_ptr create( - Level* level, + const Level& level, const glm::ivec3& a, const glm::ivec3& b, bool crop,