From 336ae09f669fe734ac9a69ebcbb3550596f26a56 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 20:06:23 +0300 Subject: [PATCH 1/6] fix unchecked indices buffer overflow --- src/graphics/render/BlocksRenderer.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 5320edd73..5cc0bb525 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -80,7 +80,7 @@ void BlocksRenderer::face( const glm::vec4(&lights)[4], const glm::vec4& tint ) { - if (vertexCount + 4 >= capacity) { + if (vertexCount + 4 >= capacity || indexCount + 6 >= capacity) { overflow = true; return; } @@ -120,7 +120,7 @@ void BlocksRenderer::faceAO( const UVRegion& region, bool lights ) { - if (vertexCount + 4 >= capacity) { + if (vertexCount + 4 >= capacity || indexCount + 6 >= capacity) { overflow = true; return; } @@ -159,7 +159,7 @@ void BlocksRenderer::face( glm::vec4 tint, bool lights ) { - if (vertexCount + 4 >= capacity) { + if (vertexCount + 4 >= capacity || indexCount + 6 >= capacity) { overflow = true; return; } @@ -305,12 +305,15 @@ void BlocksRenderer::blockCustomModel( const auto& model = cache.getModel(block.rt.id, block.getVariantIndex(states.userbits)); for (const auto& mesh : model.meshes) { - if (vertexCount + mesh.vertices.size() >= capacity) { + if (vertexCount + mesh.vertices.size() >= capacity + || indexCount + mesh.vertices.size() >= capacity) { overflow = true; return; } bool shading = mesh.shading && !block.shadeless; - for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) { + + int trianglesCount = mesh.vertices.size() / 3; + for (int triangle = 0; triangle < trianglesCount; triangle++) { auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord - mesh.vertices[triangle * 3 + 1].coord; r = r.x * X + r.y * Y + r.z * Z; @@ -778,6 +781,10 @@ ChunkMesh BlocksRenderer::render( const Chunk* chunk, const VoxelsVolume& volume ) { build(chunk, volume); + + assert(vertexCount <= capacity); + assert(indexCount <= capacity); + assert(denseIndexCount <= capacity); return ChunkMesh{std::make_unique>( vertexBuffer.get(), vertexCount, From e451a4f3a3dcc16f8377f1b2a0098436463ac5bb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 22:43:20 +0300 Subject: [PATCH 2/6] add explicit 'solid' block property --- res/scripts/post_content.lua | 2 +- src/content/ContentBuilder.cpp | 8 ++++++-- src/content/loading/BlockLoader.cpp | 1 + src/graphics/render/BlocksRenderer.cpp | 2 +- src/voxels/Block.hpp | 3 +++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/res/scripts/post_content.lua b/res/scripts/post_content.lua index b512882d7..b6ca05598 100644 --- a/res/scripts/post_content.lua +++ b/res/scripts/post_content.lua @@ -7,7 +7,7 @@ local names = { "hidden", "draw-group", "picking-item", "surface-replacement", "script-name", "ui-layout", "inventory-size", "tick-interval", "overlay-texture", "translucent", "fields", "particles", "icon-type", "icon", "placing-block", - "stack-size", "name", "script-file", "culling" + "stack-size", "name", "script-file", "culling", "solid" } for name, _ in pairs(user_props) do table.insert(names, name) diff --git a/src/content/ContentBuilder.cpp b/src/content/ContentBuilder.cpp index 5eb639b1a..d32cb2860 100644 --- a/src/content/ContentBuilder.cpp +++ b/src/content/ContentBuilder.cpp @@ -34,11 +34,15 @@ std::unique_ptr ContentBuilder::build() { if (def.variants) { for (auto& variant : def.variants->variants) { - variant.rt.solid = variant.model.type == BlockModelType::BLOCK; + variant.rt.solid = + variant.model.type == BlockModelType::BLOCK || + def.explictlySolid; } def.defaults = def.variants->variants.at(0); } else { - def.defaults.rt.solid = def.defaults.model.type == BlockModelType::BLOCK; + def.defaults.rt.solid = + def.defaults.model.type == BlockModelType::BLOCK || + def.explictlySolid; } const float EPSILON = 0.01f; diff --git a/src/content/loading/BlockLoader.cpp b/src/content/loading/BlockLoader.cpp index 6866443bc..87c10fa67 100644 --- a/src/content/loading/BlockLoader.cpp +++ b/src/content/loading/BlockLoader.cpp @@ -227,6 +227,7 @@ template<> void ContentUnitLoader::loadUnit( root.at("tick-interval").get(def.tickInterval); root.at("overlay-texture").get(def.overlayTexture); root.at("translucent").get(def.translucent); + root.at("solid").get(def.explictlySolid); if (root.has("fields")) { def.dataStruct = std::make_unique(); diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 5cc0bb525..1980a5d97 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -331,7 +331,7 @@ void BlocksRenderer::blockCustomModel( if (!block.rt.extended && !isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant) - && is_aligned(n)) { + /*&& is_aligned(n)*/) { continue; } diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 29eda2494..96620c8f9 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -230,6 +230,9 @@ public: /// @brief Block has semi-transparent texture bool translucent = false; + /// @brief Explicitly overriding 'solid' property if true assigned + bool explictlySolid = false; + /// @brief Set of block physical hitboxes std::vector hitboxes {AABB()}; From a95afd777d80185b9ecac3565a3c237cd21f8b51 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 23:24:38 +0300 Subject: [PATCH 3/6] update Block::cloneTo --- src/graphics/render/BlocksRenderer.cpp | 3 +-- src/voxels/Block.cpp | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 1980a5d97..503326b14 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -330,8 +330,7 @@ void BlocksRenderer::blockCustomModel( vp = vp.x * X + vp.y * Y + vp.z * Z; if (!block.rt.extended - && !isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant) - /*&& is_aligned(n)*/) { + && !isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant)) { continue; } diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index 17a3acc46..65830efc5 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -125,9 +125,6 @@ Block::Block(std::string name, const std::string& texture) void Block::cloneTo(Block& dst) { dst.caption = caption; - for (int i = 0; i < 6; i++) { - dst.defaults = defaults; - } dst.defaults = defaults; if (variants) { dst.variants = std::make_unique(*variants); @@ -155,6 +152,7 @@ void Block::cloneTo(Block& dst) { dst.tickInterval = tickInterval; dst.overlayTexture = overlayTexture; dst.translucent = translucent; + dst.explictlySolid = explictlySolid; dst.tags = tags; if (particles) { dst.particles = std::make_unique(*particles); From 9bc1e987d12f44045c6f3fae1326f597e4629ab3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 23:34:12 +0300 Subject: [PATCH 4/6] update doc/*/block-properties.md --- doc/en/block-properties.md | 5 +++++ doc/ru/block-properties.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index 6233ea7ec..72a4b4c48 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -56,6 +56,11 @@ Enables translucency support in block textures (examples: water, ice). Should only be used when needed, as it impacts performance. Not required for full transparency (grass, flowers). +### *solid* + +Explicitly specifies that the block is solid - completely overlapping the blocks behind it. +Used by blocks with the `custom` model type, which must support culling of invisible geometry, as with the `block` type. If `false` specified then ignored. + ### *rotation* Rotation profile (set of available block rotations and behaviour of placing block rotation) from list: diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index b70c5376d..97e8fedc6 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -57,6 +57,11 @@ Следует использовать только при надобности, так как влияет на производительность. Не требуется для полной прозрачности (трава, цветы). +### Цельность - *solid* + +Явно указывает, что блок является цельным (полным) - полностью перекрывает блоки за собой. +Используется блоками с типом модели `custom`, которые должны поддерживать отсечение невидимой геометрии, как у типа `block`. Свойство игнорируется при указании `false`. + ### Вращение - *rotation* Профиль вращения (набор положений, в которые можно установить блок) из списка: From 19836bfde3eb2a0724de28da3661517127d7defd Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 23:37:47 +0300 Subject: [PATCH 5/6] remove unused `is_aligned` --- src/graphics/render/BlocksRenderer.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 503326b14..2f700d659 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -274,19 +274,6 @@ void BlocksRenderer::blockAABB( } } -static bool is_aligned(const glm::vec3& v, float e = 1e-6f) { - if (std::abs(v.y) < e && std::abs(v.z) < e && std::abs(v.x) > e) { - return true; - } - if (std::abs(v.x) < e && std::abs(v.z) < e && std::abs(v.y) > e) { - return true; - } - if (std::abs(v.x) < e && std::abs(v.y) < e && std::abs(v.z) > e) { - return true; - } - return false; -} - void BlocksRenderer::blockCustomModel( const glm::ivec3& icoord, const Block& block, blockstate states, bool lights, bool ao ) { From a586fe5e92681376149061bb74a324e7d4dda15e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 8 Jan 2026 23:46:52 +0300 Subject: [PATCH 6/6] feat: custom model full culling case --- src/graphics/render/BlocksRenderer.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 2f700d659..36f12a196 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -290,6 +290,23 @@ void BlocksRenderer::blockCustomModel( Z = orient.axes[2]; } + if (!block.rt.extended) { + glm::ivec3 offsets[6] { + {-1, 0, 0}, {0, -1, 0}, {0, 0, -1}, + {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, + }; + bool culled = true; + for (int i = 0; i < 6; i++) { + if (isOpen(icoord + offsets[i], block, variant)) { + culled = false; + break; + } + } + if (culled) { + return; + } + } + const auto& model = cache.getModel(block.rt.id, block.getVariantIndex(states.userbits)); for (const auto& mesh : model.meshes) { if (vertexCount + mesh.vertices.size() >= capacity