From ded0964827f77dce8eaaf064294ae173c1e190f3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 28 Feb 2026 00:27:08 +0300 Subject: [PATCH 1/7] feat: keeping assets alive during current frame (temporary solution) --- src/assets/Assets.cpp | 11 ++++++++++- src/assets/Assets.hpp | 16 +++++++++++++--- src/engine/AssetsManagement.cpp | 3 ++- src/engine/AssetsManagement.hpp | 2 ++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index 993e7360c..45db15945 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -1,6 +1,15 @@ #include "Assets.hpp" -Assets::~Assets() = default; +Assets::Assets(util::ObjectsKeeper& vault) : vault(vault) { +} + +Assets::~Assets() { + for (auto& [_, map] : assets) { + for (auto& [__, asset] : map) { + vault.keepAlive(std::move(asset)); + } + } +} const std::vector& Assets::getAnimations() { return animations; diff --git a/src/assets/Assets.hpp b/src/assets/Assets.hpp index ea0753aec..06372551e 100644 --- a/src/assets/Assets.hpp +++ b/src/assets/Assets.hpp @@ -12,6 +12,7 @@ #include #include "util/stringutil.hpp" +#include "util/ObjectsKeeper.hpp" #include "graphics/core/TextureAnimation.hpp" class Assets; @@ -64,13 +65,14 @@ namespace assetload { } class Assets { + util::ObjectsKeeper& vault; std::vector animations; using assets_map = std::unordered_map>; std::unordered_map assets; std::vector setupFuncs; public: - Assets() = default; + Assets(util::ObjectsKeeper& vault); Assets(const Assets&) = delete; ~Assets(); @@ -79,12 +81,20 @@ public: template void store(std::unique_ptr asset, const std::string& name) { - assets[typeid(T)][name].reset(asset.release()); + auto& dst = assets[typeid(T)][name]; + if (dst != nullptr) { + vault.keepAlive(std::move(dst)); + } + dst.reset(asset.release()); } template void store(std::shared_ptr asset, const std::string& name) { - assets[typeid(T)][name] = std::move(asset); + auto& dst = assets[typeid(T)][name]; + if (dst != nullptr) { + vault.keepAlive(std::move(dst)); + } + dst = std::move(asset); } template diff --git a/src/engine/AssetsManagement.cpp b/src/engine/AssetsManagement.cpp index 578a0e45b..b5fd9e7c5 100644 --- a/src/engine/AssetsManagement.cpp +++ b/src/engine/AssetsManagement.cpp @@ -51,7 +51,7 @@ void AssetsManagement::loadAssets(Content* content) { logger.info() << "loading assets"; Shader::preprocessor->setPaths(&paths.resPaths); - auto new_assets = std::make_unique(); + auto new_assets = std::make_unique(assetsVault); AssetsLoader loader(engine, *new_assets, paths.resPaths); AssetsLoader::addDefaults(loader, content); @@ -78,6 +78,7 @@ void AssetsManagement::loadAssets(Content* content) { } void AssetsManagement::update() { + assetsVault.clearKeepedObjects(); if (backgroundLoaderTask) { backgroundLoaderTask->update(); } diff --git a/src/engine/AssetsManagement.hpp b/src/engine/AssetsManagement.hpp index 4e14c9305..81c33bef8 100644 --- a/src/engine/AssetsManagement.hpp +++ b/src/engine/AssetsManagement.hpp @@ -1,6 +1,7 @@ #pragma once #include "assets/Assets.hpp" +#include "util/ObjectsKeeper.hpp" #include @@ -30,4 +31,5 @@ private: std::unique_ptr assets; std::unique_ptr backgroundLoader; std::shared_ptr backgroundLoaderTask; + util::ObjectsKeeper assetsVault; }; From 0cc8c70a1704bf511635c1c1e19fe707e8477127 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Sat, 28 Feb 2026 15:59:04 +0200 Subject: [PATCH 2/7] fix blocks variants --- doc/en/scripting/builtins/libblock.md | 2 +- doc/ru/scripting/builtins/libblock.md | 2 +- src/content/loading/BlockLoader.cpp | 4 +-- src/frontend/ContentGfxCache.cpp | 2 +- src/graphics/render/ModelsGenerator.cpp | 6 +++++ src/logic/scripting/lua/libs/libblock.cpp | 30 ++++++++++++++++++++--- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md index b2528c364..db407e92a 100644 --- a/doc/en/scripting/builtins/libblock.md +++ b/doc/en/scripting/builtins/libblock.md @@ -67,7 +67,7 @@ block.get_picking_item(id: int) -> int block.get_variant(x: int, y: int, z: int) -> int -- Sets the block variant by index -block.set_variant(x: int, y: int, z: int, index: int) -> int +block.set_variant(x: int, y: int, z: int, index: int) -- Checks if an block has specified tag block.has_tag(id: int, tag: str) -> bool diff --git a/doc/ru/scripting/builtins/libblock.md b/doc/ru/scripting/builtins/libblock.md index a82d2ff66..b7af3e462 100644 --- a/doc/ru/scripting/builtins/libblock.md +++ b/doc/ru/scripting/builtins/libblock.md @@ -46,7 +46,7 @@ block.destruct(x: int, y: int, z: int, playerid: int) block.get_variant(x: int, y: int, z: int) -> int -- Устанавливает вариант блока по индексу -block.set_variant(x: int, y: int, z: int, index: int) -> int +block.set_variant(x: int, y: int, z: int, index: int) ``` > [!WARNING] diff --git a/src/content/loading/BlockLoader.cpp b/src/content/loading/BlockLoader.cpp index 87c10fa67..c4df790c6 100644 --- a/src/content/loading/BlockLoader.cpp +++ b/src/content/loading/BlockLoader.cpp @@ -120,8 +120,8 @@ template<> void ContentUnitLoader::loadUnit( } def.variants = std::make_unique(); - def.variants->offset = 0; - def.variants->mask = 0xF; + def.variants->offset = offset; + def.variants->mask = (1ULL << bitsCount) - 1; def.variants->variants.push_back(def.defaults); for (int i = 0; i < variants.size(); i++) { Variant variant = def.defaults; diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 20b7cdaa7..b8ce69a5f 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -70,7 +70,7 @@ void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) { refreshVariant(def, def.defaults, 0, atlas); if (def.variants) { const auto& variants = def.variants->variants; - for (int i = 1; i < variants.size() - 1; i++) { + for (int i = 1; i < variants.size(); i++) { refreshVariant(def, variants[i], i, atlas); } def.variants->variants.at(0) = def.defaults; diff --git a/src/graphics/render/ModelsGenerator.cpp b/src/graphics/render/ModelsGenerator.cpp index b4f423480..da82680bb 100644 --- a/src/graphics/render/ModelsGenerator.cpp +++ b/src/graphics/render/ModelsGenerator.cpp @@ -92,6 +92,12 @@ void ModelsGenerator::prepareModel( void ModelsGenerator::prepare(Content& content, Assets& assets) { for (auto& [name, def] : content.blocks.getDefs()) { prepareModel(assets, *def, def->defaults, 0); + if (def->variants) { + auto& variants = def->variants->variants; + for (int i = 1; i < variants.size(); i++) { + prepareModel(assets, *def, variants[i], i); + } + } } for (auto& [name, def] : content.items.getDefs()) { assets.store( diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index 6a84b4113..2fa2b1281 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -246,11 +246,12 @@ static int l_get_user_bits(lua::State* L) { } static int l_get_variant(lua::State* L) { + auto& chunks = *level->chunks; auto x = lua::tointeger(L, 1); auto y = lua::tointeger(L, 2); auto z = lua::tointeger(L, 3); - auto vox = blocks_agent::get(*level->chunks, x, y, z); + auto vox = blocks_agent::get(chunks, x, y, z); if (vox == nullptr) { return lua::pushinteger(L, 0); } @@ -258,6 +259,13 @@ static int l_get_variant(lua::State* L) { if (def.variants == nullptr) { return lua::pushinteger(L, 0); } + if (def.rt.extended) { + auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state); + vox = blocks_agent::get(chunks, origin.x, origin.y, origin.z); + if (vox == nullptr) { + return lua::pushinteger(L, 0); + } + } return lua::pushinteger( L, (vox->state.userbits >> def.variants->offset) & def.variants->mask ); @@ -290,6 +298,14 @@ static int l_set_user_bits(lua::State* L) { if (vox == nullptr) { return 0; } + int ocx = floordiv(origin.x); + int ocz = floordiv(origin.z); + if (cx != ocx || cz != ocz) { + chunk = blocks_agent::get_chunk(chunks, ocx, ocz); + if (chunk == nullptr) { + return 0; + } + } } vox->state.userbits = (vox->state.userbits & (~mask)) | value; chunk->setModifiedAndUnsaved(); @@ -318,8 +334,8 @@ static int l_set_variant(lua::State* L) { } auto offset = def.variants->offset; - auto mask = def.variants->mask; - auto value = (lua::tointeger(L, 4) << offset) & mask; + auto mask = def.variants->mask << offset; + auto value = (lua::tointeger(L, 4) << offset); if (def.rt.extended) { auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state); @@ -327,6 +343,14 @@ static int l_set_variant(lua::State* L) { if (vox == nullptr) { return 0; } + int ocx = floordiv(origin.x); + int ocz = floordiv(origin.z); + if (cx != ocx || cz != ocz) { + chunk = blocks_agent::get_chunk(chunks, ocx, ocz); + if (chunk == nullptr) { + return 0; + } + } } vox->state.userbits = (vox->state.userbits & (~mask)) | value; chunk->setModifiedAndUnsaved(); From 0b7dc14f5512478c7b7df408bab007d06de6f9ae Mon Sep 17 00:00:00 2001 From: clasher113 Date: Sat, 28 Feb 2026 18:31:15 +0200 Subject: [PATCH 3/7] fix extended block grounding (new block property) --- doc/en/block-properties.md | 9 +++++ doc/ru/block-properties.md | 8 +++++ src/content/loading/BlockLoader.cpp | 9 +++++ src/logic/BlocksController.cpp | 15 +++++--- src/logic/PlayerController.cpp | 6 ++-- src/voxels/Block.hpp | 19 +++++++++++ src/voxels/blocks_agent.hpp | 53 +++++++++++++++++++++++++++++ 7 files changed, 111 insertions(+), 8 deletions(-) diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index 72a4b4c48..f3137dd60 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -241,6 +241,15 @@ Number of block inventory slots. Default - 0 (no inventory). Array of three integers. Default value is `[1, 1, 1]`. +### *grounding-behaviour* + +Defines the behavior of the extended grounded block. Available behavior options: + +- "partial" - at least one segment must be grounded (default) +- "complete" - all segments must be grounded +- "origin" - origin segment must be grounded + + ## Block fields Block fields allow you to write more data unique to a specified voxel than the user bits allow. diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index 97e8fedc6..50bd7f023 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -247,6 +247,14 @@ Массив из трех целых чисел. Значение по-умолчанию - `[1, 1, 1]`. +### Поведение приземленности - *grounding-behaviour* + +Определяет поведение расширенного приземленного блока. Доступные варианты поведения: + +- "partial" - как минимум один сегмент блока должен быть приземленным (по-умолчанию) +- "complete" - все сегменты блока должны быть приземленными +- "origin" - главный сегмент должен быть приземленным + ## Поля блока Поля блоков позволяет записывать больше уникальных для конкретного блока данных, чем это позволяют пользовательские биты. diff --git a/src/content/loading/BlockLoader.cpp b/src/content/loading/BlockLoader.cpp index c4df790c6..d9bb5e536 100644 --- a/src/content/loading/BlockLoader.cpp +++ b/src/content/loading/BlockLoader.cpp @@ -206,6 +206,15 @@ template<> void ContentUnitLoader::loadUnit( def.defaults.model.type = BlockModelType::AABB; def.hitboxes = {AABB(def.size)}; } + + // grounding behaviour + if (root.has("grounding-behaviour")) { + std::string groundingBehaviourName = GroundingBehaviourMeta.getNameString(def.groundingBehaviour); + root.at("grounding-behaviour").get(groundingBehaviourName); + if (!GroundingBehaviourMeta.getItem(groundingBehaviourName, def.groundingBehaviour)) { + logger.error() << "unknown grounding behaviour: " << groundingBehaviourName; + } + } } // primitive properties diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 1e3ad2441..46c27ec7f 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -106,10 +106,17 @@ void BlocksController::updateBlock(int x, int y, int 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 (!blocks_agent::is_solid_at(chunks, x + vec.x, y + vec.y, z + vec.z)) { - breakBlock(nullptr, def, x, y, z); - return; + if (def.rt.extended) { + auto origin = blocks_agent::seek_origin(chunks, {x, y, z}, def, vox->state); + if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, origin)) { + breakBlock(nullptr, def, origin.x, origin.y, origin.z); + return; + } + } else { + if (!blocks_agent::check_grounding(chunks, def, vox->state.rotation, {x, y, z})) { + breakBlock(nullptr, def, x, y, z); + return; + } } } if (def.rt.funcsset.update) { diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 17c4fe23f..2e6e6e7e2 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -22,6 +22,7 @@ #include "scripting/scripting.hpp" #include "settings.hpp" #include "voxels/Block.hpp" +#include "voxels/blocks_agent.hpp" #include "voxels/Chunks.hpp" #include "voxels/voxel.hpp" #include "window/Camera.hpp" @@ -448,10 +449,7 @@ void PlayerController::processRightClick( return; } if (def.grounded) { - const auto& vec = get_ground_direction(def, state.rotation); - if (!chunks.isSolidBlock( - coord.x + vec.x, coord.y + vec.y, coord.z + vec.z - )) { + if (!blocks_agent::check_grounding(chunks, def, state.rotation, coord)) { return; } } diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index e1a68c28f..5ba3bb267 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -140,6 +140,22 @@ VC_ENUM_METADATA(CullingMode) {"disabled", CullingMode::DISABLED}, VC_ENUM_END +/// @brief Grounding behaviour for extended blocks +enum class GroundingBehaviour : uint8_t { + /// @brief at least one segment must be grounded + PARTIAL, + /// @brief all segments must be grounded + COMPLETE, + /// @brief origin segment must be grounded + ORIGIN +}; + +VC_ENUM_METADATA(GroundingBehaviour) + {"partial", GroundingBehaviour::PARTIAL}, + {"complete", GroundingBehaviour::COMPLETE}, + {"origin", GroundingBehaviour::ORIGIN}, +VC_ENUM_END + /// @brief Common kit of block properties applied to groups of blocks struct BlockMaterial : Serializable { std::string name; @@ -239,6 +255,9 @@ public: /// @brief Explicitly overriding 'solid' property if true assigned bool explictlySolid = false; + /// @brief Grounding behaviour + GroundingBehaviour groundingBehaviour = GroundingBehaviour::PARTIAL; + /// @brief Set of block physical hitboxes std::vector hitboxes {AABB()}; diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index 9ffac7f93..a8131e820 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -494,4 +494,57 @@ inline const AABB* is_obstacle_at(const Storage& chunks, float x, float y, float return nullptr; } +/// @brief Check block grounding +/// @tparam Storage chunks storage class +/// @param chunks chunks storage +/// @param def block definition +/// @param rotationIndex target block rotation index +/// @param origin target block origin +/// @return true if grounded +template +inline bool check_grounding( + const Storage& chunks, + const Block& def, + uint8_t rotationIndex, + const glm::ivec3& origin +) { + const auto& vec = get_ground_direction(def, rotationIndex); + + if (def.rt.extended) { + const auto& rotation = def.rotations.variants[rotationIndex]; + + if (def.groundingBehaviour == GroundingBehaviour::PARTIAL) { + for (int sz = 0; sz < def.size.z; sz++) { + for (int sx = 0; sx < def.size.x; sx++) { + auto pos = origin; + pos += rotation.axes[0] * sx; + pos += rotation.axes[2] * sz; + if (blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) { + return true; + } + } + } + return false; + } + else if (def.groundingBehaviour == GroundingBehaviour::COMPLETE) { + for (int sz = 0; sz < def.size.z; sz++) { + for (int sx = 0; sx < def.size.x; sx++) { + auto pos = origin; + pos += rotation.axes[0] * sx; + pos += rotation.axes[2] * sz; + if (!blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) { + return false; + } + } + } + return true; + } + else if (def.groundingBehaviour == GroundingBehaviour::ORIGIN) { + return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z); + } + } + + return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z); +} + } // blocks_agent From 31cb9ebd23e286d64c77be32ff8c8c04df8acf4b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 1 Mar 2026 21:11:58 +0300 Subject: [PATCH 4/7] add 'system.preserve-assets-during-frame' setting --- src/assets/Assets.cpp | 8 ++++++-- src/assets/Assets.hpp | 12 ++++++------ src/engine/AssetsManagement.cpp | 4 +++- src/io/settings_io.cpp | 1 + src/settings.hpp | 3 +++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp index 45db15945..3e0776747 100644 --- a/src/assets/Assets.cpp +++ b/src/assets/Assets.cpp @@ -1,13 +1,17 @@ #include "Assets.hpp" -Assets::Assets(util::ObjectsKeeper& vault) : vault(vault) { +Assets::Assets(util::ObjectsKeeper* vault) : vault(vault) { } Assets::~Assets() { + if (vault == nullptr) { + return; + } for (auto& [_, map] : assets) { for (auto& [__, asset] : map) { - vault.keepAlive(std::move(asset)); + vault->keepAlive(std::move(asset)); } + map.clear(); } } diff --git a/src/assets/Assets.hpp b/src/assets/Assets.hpp index 06372551e..b9faa877f 100644 --- a/src/assets/Assets.hpp +++ b/src/assets/Assets.hpp @@ -65,14 +65,14 @@ namespace assetload { } class Assets { - util::ObjectsKeeper& vault; + util::ObjectsKeeper* vault; std::vector animations; using assets_map = std::unordered_map>; std::unordered_map assets; std::vector setupFuncs; public: - Assets(util::ObjectsKeeper& vault); + Assets(util::ObjectsKeeper* vault); Assets(const Assets&) = delete; ~Assets(); @@ -82,8 +82,8 @@ public: template void store(std::unique_ptr asset, const std::string& name) { auto& dst = assets[typeid(T)][name]; - if (dst != nullptr) { - vault.keepAlive(std::move(dst)); + if (vault != nullptr && dst != nullptr) { + vault->keepAlive(std::move(dst)); } dst.reset(asset.release()); } @@ -91,8 +91,8 @@ public: template void store(std::shared_ptr asset, const std::string& name) { auto& dst = assets[typeid(T)][name]; - if (dst != nullptr) { - vault.keepAlive(std::move(dst)); + if (vault != nullptr && dst != nullptr) { + vault->keepAlive(std::move(dst)); } dst = std::move(asset); } diff --git a/src/engine/AssetsManagement.cpp b/src/engine/AssetsManagement.cpp index b5fd9e7c5..1ca1935c9 100644 --- a/src/engine/AssetsManagement.cpp +++ b/src/engine/AssetsManagement.cpp @@ -51,7 +51,9 @@ void AssetsManagement::loadAssets(Content* content) { logger.info() << "loading assets"; Shader::preprocessor->setPaths(&paths.resPaths); - auto new_assets = std::make_unique(assetsVault); + auto new_assets = std::make_unique( + settings.system.preserveAssetsDuringFrame.get() ? &assetsVault : nullptr + ); AssetsLoader loader(engine, *new_assets, paths.resPaths); AssetsLoader::addDefaults(loader, content); diff --git a/src/io/settings_io.cpp b/src/io/settings_io.cpp index af4547a14..c66b5c451 100644 --- a/src/io/settings_io.cpp +++ b/src/io/settings_io.cpp @@ -100,6 +100,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) { builder.addSection("system"); builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders); + builder.add("preserve-assets-during-frame", &settings.system.preserveAssetsDuringFrame); } dv::value SettingsHandler::getValue(const std::string& name) const { diff --git a/src/settings.hpp b/src/settings.hpp index 331ff3ee8..782330f14 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -122,7 +122,10 @@ struct NetworkSettings { }; struct SystemSettings { + /// @brief Max background assets loaders IntegerSetting maxBgAssetLoaders {3, -4, 16}; + /// @brief Preserve assets during current frame from being destroyed + FlagSetting preserveAssetsDuringFrame {true}; }; struct EngineSettings { From 9628177698b29488965bffc60fa305e752245c13 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 1 Mar 2026 21:46:43 +0300 Subject: [PATCH 5/7] fix: missing extended block size limit check --- src/constants.hpp | 2 ++ src/content/loading/BlockLoader.cpp | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/constants.hpp b/src/constants.hpp index 501c5f62e..3ec66c259 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -33,6 +33,8 @@ inline constexpr int CHUNK_W = 16; inline constexpr int CHUNK_H = 256; inline constexpr int CHUNK_D = 16; +inline constexpr int EXTENDED_BLOCK_LIMIT = CHUNK_W; // must not be greater than chunk width and depth + inline constexpr uint VOXEL_USER_BITS = 8; inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS; diff --git a/src/content/loading/BlockLoader.cpp b/src/content/loading/BlockLoader.cpp index 87c10fa67..3bacf9d9f 100644 --- a/src/content/loading/BlockLoader.cpp +++ b/src/content/loading/BlockLoader.cpp @@ -12,6 +12,7 @@ #include "presets/ParticlesPreset.hpp" #include "util/stringutil.hpp" #include "voxels/Block.hpp" +#include "constants.hpp" using namespace data; @@ -184,7 +185,11 @@ template<> void ContentUnitLoader::loadUnit( if (auto found = root.at("emission")) { const auto& emissionarr = *found; for (size_t i = 0; i < 3; i++) { - def.emission[i] = glm::clamp(emissionarr[i].asInteger(), static_cast(0), static_cast(15)); + def.emission[i] = glm::clamp( + emissionarr[i].asInteger(), + static_cast(0), + static_cast(15) + ); } } @@ -199,7 +204,16 @@ template<> void ContentUnitLoader::loadUnit( "block " + util::quote(def.name) + ": invalid block size" ); } - + + if (def.size.x > EXTENDED_BLOCK_LIMIT || + def.size.y > EXTENDED_BLOCK_LIMIT || + def.size.z > EXTENDED_BLOCK_LIMIT) { + throw std::runtime_error( + "extended block " + util::quote(def.name) + " size limit " + + std::to_string(EXTENDED_BLOCK_LIMIT) + " exceeded" + ); + } + // should variant modify hitbox? if (def.defaults.model.type == BlockModelType::BLOCK && (def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) { From 6bdbf5b40e283b8e31ec536dcc10a1a8e0ec4875 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 2 Mar 2026 01:13:45 +0300 Subject: [PATCH 6/7] format blocks_agent.hpp --- src/voxels/blocks_agent.hpp | 111 ++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index a8131e820..0742a7293 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -2,23 +2,23 @@ /// blocks_agent is set of templates but not a class to minimize OOP overhead. -#include "voxel.hpp" #include "Block.hpp" #include "Chunk.hpp" #include "Chunks.hpp" -#include "VoxelsVolume.hpp" -#include "GlobalChunks.hpp" #include "constants.hpp" -#include "typedefs.hpp" #include "content/Content.hpp" +#include "GlobalChunks.hpp" #include "maths/voxmaths.hpp" +#include "typedefs.hpp" +#include "voxel.hpp" +#include "VoxelsVolume.hpp" #include -#include #include -#include -#include #include +#include +#include +#include struct AABB; @@ -96,7 +96,6 @@ inline const Block& get_block_def(const Storage& chunks, blockid_t id) { return chunks.getContentIndices().blocks.require(id); } - /// @brief Check if block at specified position is solid. /// @tparam Storage chunks storage class /// @param chunks chunks storage @@ -104,8 +103,10 @@ inline const Block& get_block_def(const Storage& chunks, blockid_t id) { /// @param y position Y /// @param z position Z /// @return true if block exists and solid -template -inline bool is_solid_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) { +template +inline bool is_solid_at( + const Storage& chunks, int32_t x, int32_t y, int32_t z +) { if (auto vox = get(chunks, x, y, z)) { return get_block_def(chunks, vox->id).rt.solid; } @@ -119,8 +120,10 @@ inline bool is_solid_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) /// @param y position Y /// @param z position Z /// @return true if block exists and replaceable -template -inline bool is_replaceable_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) { +template +inline bool is_replaceable_at( + const Storage& chunks, int32_t x, int32_t y, int32_t z +) { if (auto vox = get(chunks, x, y, z)) { return get_block_def(chunks, vox->id).replaceable; } @@ -456,12 +459,18 @@ voxel* raycast( bool includeNonSelectable ); -void get_voxels(const Chunks& chunks, VoxelsVolume* volume, bool backlight=false); +void get_voxels( + const Chunks& chunks, VoxelsVolume* volume, bool backlight = false +); -void get_voxels(const GlobalChunks& 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) { +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); @@ -510,41 +519,47 @@ inline bool check_grounding( ) { const auto& vec = get_ground_direction(def, rotationIndex); - if (def.rt.extended) { - const auto& rotation = def.rotations.variants[rotationIndex]; - - if (def.groundingBehaviour == GroundingBehaviour::PARTIAL) { - for (int sz = 0; sz < def.size.z; sz++) { - for (int sx = 0; sx < def.size.x; sx++) { - auto pos = origin; - pos += rotation.axes[0] * sx; - pos += rotation.axes[2] * sz; - if (blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) { - return true; - } - } - } - return false; - } - else if (def.groundingBehaviour == GroundingBehaviour::COMPLETE) { - for (int sz = 0; sz < def.size.z; sz++) { - for (int sx = 0; sx < def.size.x; sx++) { - auto pos = origin; - pos += rotation.axes[0] * sx; - pos += rotation.axes[2] * sz; - if (!blocks_agent::is_solid_at(chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z)) { - return false; - } - } - } - return true; - } - else if (def.groundingBehaviour == GroundingBehaviour::ORIGIN) { - return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z); - } + if (!def.rt.extended) { + return blocks_agent::is_solid_at( + chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z + ); } - return blocks_agent::is_solid_at(chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z); + const auto& rotation = def.rotations.variants[rotationIndex]; + + if (def.groundingBehaviour == GroundingBehaviour::PARTIAL) { + for (int sz = 0; sz < def.size.z; sz++) { + for (int sx = 0; sx < def.size.x; sx++) { + auto pos = origin; + pos += rotation.axes[0] * sx; + pos += rotation.axes[2] * sz; + if (blocks_agent::is_solid_at( + chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z + )) { + return true; + } + } + } + return false; + } else if (def.groundingBehaviour == GroundingBehaviour::COMPLETE) { + for (int sz = 0; sz < def.size.z; sz++) { + for (int sx = 0; sx < def.size.x; sx++) { + auto pos = origin; + pos += rotation.axes[0] * sx; + pos += rotation.axes[2] * sz; + if (!blocks_agent::is_solid_at( + chunks, pos.x + vec.x, pos.y + vec.y, pos.z + vec.z + )) { + return false; + } + } + } + return true; + } else { + return blocks_agent::is_solid_at( + chunks, origin.x + vec.x, origin.y + vec.y, origin.z + vec.z + ); + } } } // blocks_agent From cb2b90198510dd83ab4ce14fc82a55c08b7c0453 Mon Sep 17 00:00:00 2001 From: ChancellorIkseew <156004311+ChancellorIkseew@users.noreply.github.com> Date: Mon, 2 Mar 2026 08:18:47 +1000 Subject: [PATCH 7/7] PlayerContoroller and LevelScreen refactoring (#806) --- src/frontend/screens/LevelScreen.cpp | 30 ++++++++++++++-------------- src/logic/PlayerController.cpp | 12 +++++------ src/logic/PlayerController.hpp | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index acb3edf70..13618d33a 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -114,7 +114,7 @@ LevelScreen::~LevelScreen() { } scripting::on_frontend_close(); input.getBindings().enableAll(); - playerController->getPlayer()->chunks->saveAndClear(); + playerController->getPlayer().chunks->saveAndClear(); controller->onWorldQuit(); } @@ -168,12 +168,12 @@ void LevelScreen::saveDecorations() { void LevelScreen::saveWorldPreview() { try { logger.info() << "saving world preview"; - auto player = playerController->getPlayer(); - auto& settings = engine.getSettings(); + const Player& player = playerController->getPlayer(); + const auto& settings = engine.getSettings(); int previewSize = settings.ui.worldPreviewSize.get(); // camera special copy for world preview - Camera camera = *player->fpCamera; + Camera& camera = *player.fpCamera; camera.setFov(glm::radians(70.0f)); DrawContext pctx(nullptr, engine.getWindow(), batch.get()); @@ -215,18 +215,18 @@ void LevelScreen::updateHotkeys() { } void LevelScreen::updateAudio() { - auto player = playerController->getPlayer(); - auto camera = player->currentCamera; + Player& player = playerController->getPlayer(); + Camera& camera = *player.currentCamera; bool paused = hud->isPause(); audio::get_channel("regular")->setPaused(paused); audio::get_channel("ambient")->setPaused(paused); glm::vec3 velocity {}; - if (auto hitbox = player->getHitbox()) { + if (auto hitbox = player.getHitbox()) { velocity = hitbox->velocity; } audio::set_listener( - camera->position, velocity, camera->dir, glm::vec3(0, 1, 0) + camera.position, velocity, camera.dir, glm::vec3(0, 1, 0) ); } @@ -257,22 +257,22 @@ void LevelScreen::update(float delta) { hud->update(hudVisible); - const auto& weather = renderer->getWeather(); - const auto& player = *playerController->getPlayer(); - const auto& camera = *player.currentCamera; + const Weather& weather = renderer->getWeather(); + const Player& player = playerController->getPlayer(); + const Camera& camera = *player.currentCamera; decorator->update(paused ? 0.0f : delta, camera, weather); } void LevelScreen::draw(float delta) { - auto camera = playerController->getPlayer()->currentCamera; + Camera& camera = *playerController->getPlayer().currentCamera; - DrawContext ctx(nullptr, engine.getWindow(), batch.get()); + const DrawContext ctx(nullptr, engine.getWindow(), batch.get()); if (!hud->isPause()) { scripting::on_entities_render(engine.getTime().getDelta()); } - renderer->update(*camera, delta * !hud->isPause()); - renderer->renderFrame(ctx, *camera, hudVisible, *postProcessing); + renderer->update(camera, delta * !hud->isPause()); + renderer->renderFrame(ctx, camera, hudVisible, *postProcessing); if (!hud->isPause()) { scripting::on_frontend_render(); } diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 2e6e6e7e2..e707d1637 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -253,18 +253,18 @@ void PlayerController::onFootstep(const Hitbox& hitbox) { } void PlayerController::updateFootsteps(float delta) { - const float pi = glm::pi(); + constexpr float GLM_PI = glm::pi(); auto hitbox = player.getHitbox(); if (hitbox && hitbox->grounded) { const glm::vec3& vel = hitbox->velocity; float f = glm::length(glm::vec2(vel.x, vel.z)); stepsTimer += delta * f * STEPS_SPEED; - if (stepsTimer >= pi) { - stepsTimer = fmod(stepsTimer, pi); + if (stepsTimer >= GLM_PI) { + stepsTimer = fmod(stepsTimer, GLM_PI); onFootstep(*hitbox); } } else { - stepsTimer = pi; + stepsTimer = GLM_PI; } } @@ -554,6 +554,6 @@ void PlayerController::updateInteraction(const Input& inputEvents, float delta) } } -Player* PlayerController::getPlayer() { - return &player; +Player& PlayerController::getPlayer() { + return player; } diff --git a/src/logic/PlayerController.hpp b/src/logic/PlayerController.hpp index 7f895ee3c..e730ff37c 100644 --- a/src/logic/PlayerController.hpp +++ b/src/logic/PlayerController.hpp @@ -89,5 +89,5 @@ public: void postUpdate( float delta, int windowHeight, const Input* inputEvents, bool pause ); - Player* getPlayer(); + Player& getPlayer(); };