From 8e51f1b77c284615a5d24841b989a99bb1f2db1c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 18 Feb 2026 20:48:04 +0300 Subject: [PATCH 1/7] fix: AL_REVERB_GAIN assertion failed --- src/audio/AL/ALAudio.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/AL/ALAudio.cpp b/src/audio/AL/ALAudio.cpp index e7494d306..d05ccce58 100644 --- a/src/audio/AL/ALAudio.cpp +++ b/src/audio/AL/ALAudio.cpp @@ -803,8 +803,10 @@ void ALAudio::setAcoustics(Acoustics acoustics) { AL_CHECK(alEffectf( reverbEffect, AL_REVERB_GAIN, - glm::max(0.1f, glm::min(acoustics.reverbGain, 0.8f) * - (1.0f - glm::min(1.0f, acoustics.reverbAbsorption))) + glm::clamp(glm::min(acoustics.reverbGain, 0.8f) * + (1.0f - glm::min(1.0f, acoustics.reverbAbsorption)), + AL_REVERB_MIN_GAIN, + AL_REVERB_MAX_GAIN) )); AL_CHECK(alEffectf( reverbEffect, From 7abbe43c3cf21bbf7afa3cf392b08e52950fa163 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 18 Feb 2026 22:32:31 +0300 Subject: [PATCH 2/7] fix extended blocks culling on chunk borders --- src/graphics/render/BlocksRenderer.cpp | 10 ++++++++-- src/graphics/render/BlocksRenderer.hpp | 2 ++ src/graphics/render/ChunksRenderer.cpp | 27 +++++++++++++++++--------- src/graphics/render/ChunksRenderer.hpp | 4 ++-- src/graphics/render/commons.hpp | 3 +++ 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 377811329..6fe0f2091 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -251,6 +251,10 @@ void BlocksRenderer::blockAABB( Z = orient.axes[2]; orient.transform(hitbox); } + if (block->rt.extended) { + meshAABB.addPoint(coord + hitbox.max()); + meshAABB.addPoint(coord + hitbox.min()); + } coord -= glm::vec3(0.5f) - hitbox.center(); if (ao) { @@ -687,6 +691,7 @@ SortingMeshData BlocksRenderer::renderTranslucent( void BlocksRenderer::build( const Chunk* chunk, const VoxelsRenderVolume& volume ) { + meshAABB = AABB(glm::vec3(CHUNK_W, CHUNK_H, CHUNK_D)); this->chunk = chunk; this->voxelsBuffer = &volume; if (voxelsBuffer->pickBlockId( @@ -767,7 +772,8 @@ ChunkMeshData BlocksRenderer::createMesh() { sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ) ), - std::move(sortingMesh) + std::move(sortingMesh), + std::move(meshAABB) }; } @@ -786,7 +792,7 @@ ChunkMesh BlocksRenderer::render( IndexBufferData {indexBuffer.get(), indexCount}, IndexBufferData {denseIndexBuffer.get(), denseIndexCount}, } - ), std::move(sortingMesh), nullptr}; + ), std::move(sortingMesh), nullptr, std::move(meshAABB)}; } size_t BlocksRenderer::getMemoryConsumption() const { diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 8af7fab7a..94b708a54 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -6,6 +6,7 @@ #include "voxels/Chunk.hpp" #include "voxels/VoxelsVolume.hpp" #include "maths/util.hpp" +#include "maths/aabb.hpp" #include "commons.hpp" #include "settings.hpp" @@ -56,6 +57,7 @@ private: bool cancelled = false; bool densePass = false; bool denseRender = false; + AABB meshAABB {}; const Chunk* chunk = nullptr; const VoxelsRenderVolume* voxelsBuffer = nullptr; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index b7ffa3715..8498091c9 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -81,7 +81,9 @@ ChunksRenderer::ChunksRenderer( meshes[result.key] = ChunkMesh { std::move(chunk), std::move(meshData.sortingMesh), - nullptr}; + nullptr, + std::move(meshData.meshAABB) + }; } inwork.erase(result.key); }, @@ -120,7 +122,7 @@ std::shared_ptr ChunksRenderer::prepareVoxelsVolume( return voxelsBuffer; } -const Mesh* ChunksRenderer::render( +const ChunkMesh* ChunksRenderer::render( const std::shared_ptr& chunk, bool important, bool lowPriority ) { glm::ivec2 key(chunk->x, chunk->z); @@ -130,7 +132,7 @@ const Mesh* ChunksRenderer::render( auto voxelsBuffer = prepareVoxelsVolume(*chunk); mesh = renderer->render(chunk.get(), *voxelsBuffer); meshes[key] = std::move(mesh); - return meshes[key].mesh.get(); + return &meshes[key]; } if (inwork.find(key) != inwork.end() || ((inwork.size() >= threadPool.getWorkersCount() || @@ -158,7 +160,7 @@ void ChunksRenderer::clear() { threadPool.clearQueue(); } -const Mesh* ChunksRenderer::getOrRender( +const ChunkMesh* ChunksRenderer::getOrRender( const std::shared_ptr& chunk, bool important, bool lowPriority ) { auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); @@ -168,7 +170,7 @@ const Mesh* ChunksRenderer::getOrRender( if (chunk->flags.modified && chunk->flags.lighted) { render(chunk, important, lowPriority); } - return found->second.mesh.get(); + return &found->second; } void ChunksRenderer::update() { @@ -211,16 +213,23 @@ const Mesh* ChunksRenderer::retrieveChunk( chunk->updateHeights(); } if (culling) { - glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); + const auto& meshAABB = mesh->meshAABB; + auto aabbMin = meshAABB.min(); + auto aabbMax = meshAABB.max(); + glm::vec3 min( + chunk->x * CHUNK_W + std::min(0.0f, aabbMin.x), + chunk->bottom, + chunk->z * CHUNK_D + std::min(0.0f, aabbMin.z) + ); glm::vec3 max( - chunk->x * CHUNK_W + CHUNK_W, + chunk->x * CHUNK_W + aabbMax.x, chunk->top, - chunk->z * CHUNK_D + CHUNK_D + chunk->z * CHUNK_D + aabbMax.z ); if (!frustum.isBoxVisible(min, max)) return nullptr; } - return mesh; + return mesh->mesh.get(); } void ChunksRenderer::drawShadowsPass( diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 4fc88ff69..5e6783d97 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -71,13 +71,13 @@ public: ); virtual ~ChunksRenderer(); - const Mesh* render( + const ChunkMesh* render( const std::shared_ptr& chunk, bool important, bool lowPriority ); void unload(const Chunk* chunk); void clear(); - const Mesh* getOrRender( + const ChunkMesh* getOrRender( const std::shared_ptr& chunk, bool important, bool lowPriority ); diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 41b352bac..52f7d5a95 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -2,6 +2,7 @@ #include "constants.hpp" #include "graphics/core/MeshData.hpp" +#include "maths/aabb.hpp" #include "util/Buffer.hpp" #include @@ -45,12 +46,14 @@ struct SortingMeshData { struct ChunkMeshData { MeshData mesh; SortingMeshData sortingMesh; + AABB meshAABB; }; struct ChunkMesh { std::unique_ptr> mesh; SortingMeshData sortingMeshData; std::unique_ptr > sortedMesh; + AABB meshAABB; }; inline constexpr int VOXELS_BUFFER_PADDING = 2; From 1cfd9fd2b1584a1ca14b3dbe15e8de7476b6b240 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 18 Feb 2026 22:41:24 +0300 Subject: [PATCH 3/7] update BlocksRenderer::blockCustomModel --- src/graphics/render/BlocksRenderer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 6fe0f2091..0aae42010 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -310,6 +310,12 @@ void BlocksRenderer::blockCustomModel( if (culled) { return; } + } else { + meshAABB.addPoint( + coord + X * glm::vec3(block.size.x) + + Y * glm::vec3(block.size.y) + + Z * glm::vec3(block.size.z) + ); } const auto& model = cache.getModel(block.rt.id, block.getVariantIndex(states.userbits)); From 471d21da98818389de64d8699f3ec160cb1fd5d1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 20 Feb 2026 17:29:08 +0300 Subject: [PATCH 4/7] add max-length to languages panel --- res/layouts/pages/languages.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layouts/pages/languages.xml b/res/layouts/pages/languages.xml index 38722bed9..4794280a5 100644 --- a/res/layouts/pages/languages.xml +++ b/res/layouts/pages/languages.xml @@ -1,3 +1,3 @@ - + From a9a5d177d5d3a57f7681ef9e18f81976f348d285 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 22 Feb 2026 14:17:09 +0300 Subject: [PATCH 5/7] add skeleton_name argument to assets.parse_model --- src/logic/scripting/lua/libs/libassets.cpp | 39 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/logic/scripting/lua/libs/libassets.cpp b/src/logic/scripting/lua/libs/libassets.cpp index 82135ad86..fa0b51cdb 100644 --- a/src/logic/scripting/lua/libs/libassets.cpp +++ b/src/logic/scripting/lua/libs/libassets.cpp @@ -70,17 +70,46 @@ static int l_parse_model(lua::State* L) { auto format = lua::require_lstring(L, 1); auto string = lua::require_lstring(L, 2); - auto name = lua::require_string(L, 3); + std::string name = lua::require_string(L, 3); + std::string skeletonName; + if (lua::isstring(L, 4)) { + skeletonName = lua::require_string(L, 4); + } + + if (format != "xml" && format != "vcm") { + throw std::runtime_error( + "unknown format " + util::quote(std::string(format)) + ); + } + + auto vcmModel = vcm::parse(name, string, format == "xml"); - if (format == "xml" || format == "vcm") { - auto vcmModel = vcm::parse(name, string, format == "xml"); + if (skeletonName.empty()) { assets.store( std::make_unique(std::move(vcmModel.squash())), name ); } else { - throw std::runtime_error( - "unknown format " + util::quote(std::string(format)) + auto skeleton = std::make_unique( + std::move(*vcmModel.skeleton) ); + if (vcmModel.parts.size() > 1) { + for (auto& [partName, model] : vcmModel.parts) { + assets.store( + std::make_unique(std::move(model)), + name + "." + partName + ); + } + for (auto& bone : skeleton->getBones()) { + bone->setModel(name + "." + bone->model.name); + } + } else { + assets.store( + std::make_unique( + std::move(vcmModel.parts["root"])), name + ); + skeleton->getRoot()->setModel(name); + } + assets.store(std::move(skeleton), skeletonName); } return 0; } From be080f90f738acecca369d76fddf47ffc2d6be69 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 22 Feb 2026 14:24:18 +0300 Subject: [PATCH 6/7] update doc/*/scripting/libassets.md --- doc/en/scripting/builtins/libassets.md | 6 +++++- doc/ru/scripting/builtins/libassets.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/en/scripting/builtins/libassets.md b/doc/en/scripting/builtins/libassets.md index 6451995b9..8f51dd762 100644 --- a/doc/en/scripting/builtins/libassets.md +++ b/doc/en/scripting/builtins/libassets.md @@ -30,7 +30,11 @@ assets.parse_model( -- Contents of the model file content: str, -- Model name after loading - name: str + name: str, + -- The skeleton name after loading. May be the same as the model name. + -- The model will be split by the named bones. + [optional] + skeleton_name: string ) -- Creates a Canvas from a loaded texture. diff --git a/doc/ru/scripting/builtins/libassets.md b/doc/ru/scripting/builtins/libassets.md index 161bb6cfb..c7f5b8620 100644 --- a/doc/ru/scripting/builtins/libassets.md +++ b/doc/ru/scripting/builtins/libassets.md @@ -31,7 +31,11 @@ assets.parse_model( -- Содержимое файла модели content: string, -- Имя модели после загрузки - name: string + name: string, + -- Имя скелета после загрузки. Может совпадать с именем модели. + -- Модель будет разделена по именованным костям. + [опционально] + skeleton_name: string ) -- Создаёт холст (Canvas) из загруженной текстуры From e4d21c940be9048076180976eaba31f0138661a3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 23 Feb 2026 17:05:13 +0300 Subject: [PATCH 7/7] fix: block inventory not removing in some cases --- src/voxels/Chunk.cpp | 5 +++-- src/voxels/Chunk.hpp | 1 + src/world/files/WorldRegions.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index 732e67a02..f49999270 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -1,13 +1,13 @@ #include "Chunk.hpp" -#include - #include "content/ContentReport.hpp" #include "items/Inventory.hpp" #include "lighting/Lightmap.hpp" #include "util/data_io.hpp" #include "voxel.hpp" +#include + Chunk::Chunk(int xpos, int zpos, std::shared_ptr lightmap) : x(xpos), z(zpos), lightmap(std::move(lightmap)) { bottom = 0; @@ -40,6 +40,7 @@ void Chunk::addBlockInventory( void Chunk::removeBlockInventory(uint x, uint y, uint z) { if (inventories.erase(vox_index(x, y, z))) { flags.unsaved = true; + flags.inventoriesRemoved = true; } } diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 5377df020..941034073 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -38,6 +38,7 @@ public: bool entities : 1; bool blocksData : 1; bool dirtyHeights : 1; + bool inventoriesRemoved : 1; } flags {}; uint64_t lastRandomTickId = -1; diff --git a/src/world/files/WorldRegions.cpp b/src/world/files/WorldRegions.cpp index 0f8535e12..14139ed37 100644 --- a/src/world/files/WorldRegions.cpp +++ b/src/world/files/WorldRegions.cpp @@ -183,7 +183,7 @@ void WorldRegions::put(Chunk* chunk, std::vector entitiesData) { LIGHTMAP_DATA_LEN); } // Writing block inventories - if (!chunk->inventories.empty()) { + if (!chunk->inventories.empty() || chunk->flags.inventoriesRemoved) { uint datasize; auto data = write_inventories(chunk->inventories, datasize); put(chunk->x,