From 5e05b44c26c1b57aaceb5e3478ccf5f98e3f14d7 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Sun, 15 Mar 2026 11:05:26 +0200 Subject: [PATCH 1/5] fix vec3 shadeless flag --- src/coders/vec3.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/coders/vec3.cpp b/src/coders/vec3.cpp index 974b9a633..e00bdd662 100644 --- a/src/coders/vec3.cpp +++ b/src/coders/vec3.cpp @@ -23,6 +23,10 @@ enum AttributeType { COLOR }; +enum MaterialFlag { + SHADELESS = 1 +}; + struct VertexAttribute { AttributeType type; int flags; @@ -62,7 +66,7 @@ static VertexAttribute load_attribute(ByteReader& reader) { static model::Mesh build_mesh( const std::vector& attrs, const util::Buffer& indices, - const std::string& texture + const Material& material ) { const glm::vec3* coords = nullptr; const glm::vec2* uvs = nullptr; @@ -112,7 +116,11 @@ static model::Mesh build_mesh( } vertices.push_back(std::move(vertex)); } - return model::Mesh {texture, std::move(vertices)}; + return model::Mesh { + material.name, + std::move(vertices), + (material.flags & MaterialFlag::SHADELESS) == 0 + }; } static model::Mesh load_mesh( @@ -154,7 +162,7 @@ static model::Mesh load_mesh( return build_mesh( attributes, indices, - materials.at(materialId).name + materials.at(materialId) ); } From 21951770ea9e0929f503acd3b14ec922f0b6c609 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Mon, 16 Mar 2026 16:27:40 +0200 Subject: [PATCH 2/5] fix block wraps high draw call count --- src/graphics/render/BlockWrapsRenderer.cpp | 44 ++++++++++++------- src/graphics/render/BlockWrapsRenderer.hpp | 15 +++---- src/graphics/render/WorldRenderer.cpp | 8 ++-- .../scripting/lua/libs/libblockwraps.cpp | 11 +++-- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp index 24a7955b8..0ed4157e4 100644 --- a/src/graphics/render/BlockWrapsRenderer.cpp +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -8,18 +8,16 @@ #include "graphics/core/DrawContext.hpp" #include "graphics/render/MainBatch.hpp" #include "lighting/Lightmap.hpp" -#include "objects/Player.hpp" #include "voxels/Block.hpp" #include "voxels/Chunks.hpp" -#include "world/Level.hpp" #include BlockWrapsRenderer::BlockWrapsRenderer( - const Assets& assets, const Level& level, const Chunks& chunks + const Assets& assets, const Content& content, const Chunks& chunks ) : assets(assets), - level(level), + content(content), chunks(chunks), batch(std::make_unique(1024)) { } @@ -43,16 +41,14 @@ void BlockWrapsRenderer::draw(BlockWrapper& wrapper, const Texture* texture) { } const voxel* vox = chunks.get(wrapper.position); - if (vox == nullptr || vox->id == BLOCK_VOID) { + if (vox == nullptr || vox->id == BLOCK_AIR) { return; } // one frame can be invalid due to texture change but ok - const auto& def = - level.content.getIndices()->blocks.require(vox->id); + const auto& def = content.getIndices()->blocks.require(vox->id); if (wrapper.modelType != def.getModel(vox->state.userbits).type) { wrapper.dirtySides = 0xFF; - refreshWrapper(wrapper); } glm::vec4 light(1, 1, 1, 0); if (wrapper.emission < 1.0f) { @@ -95,6 +91,8 @@ void BlockWrapsRenderer::draw(BlockWrapper& wrapper, const Texture* texture) { } void BlockWrapsRenderer::refreshWrapper(BlockWrapper& wrapper) { + clearOrder(&wrapper); + for (int i = 0; i < 6; i++) { if ((wrapper.cullingBits & (1 << i)) == 0) { continue; @@ -104,15 +102,19 @@ void BlockWrapsRenderer::refreshWrapper(BlockWrapper& wrapper) { wrapper.texRegions[i] = texRegion; wrapper.uvRegions[i] = texRegion.region; - renderOrder.insert({texRegion.texture, &wrapper}); + auto& wrappers = renderOrder[texRegion.texture]; + if (std::find(wrappers.begin(), wrappers.end(), &wrapper) == + wrappers.end()) { + wrappers.emplace_back(&wrapper); + } } wrapper.dirtySides = 0x0; const voxel* vox = chunks.get(wrapper.position); - if (vox == nullptr || vox->id == BLOCK_VOID) { + if (vox == nullptr || vox->id == BLOCK_AIR) { return; } - const auto& def = level.content.getIndices()->blocks.require(vox->id); + const auto& def = content.getIndices()->blocks.require(vox->id); wrapper.modelType = def.getModel(vox->state.userbits).type; switch (wrapper.modelType) { case BlockModelType::AABB: { @@ -133,7 +135,7 @@ void BlockWrapsRenderer::refreshWrapper(BlockWrapper& wrapper) { } } -void BlockWrapsRenderer::draw(const DrawContext& pctx, const Player& player) { +void BlockWrapsRenderer::draw(const DrawContext& pctx) { auto ctx = pctx.sub(); auto& shader = assets.require("entity"); @@ -146,9 +148,11 @@ void BlockWrapsRenderer::draw(const DrawContext& pctx, const Player& player) { } } - for (const auto& [texture, wrapper] : renderOrder) { + for (const auto& [texture, wrappersArray] : renderOrder) { batch->setTexture(texture); - draw(*wrapper, texture); + for (auto wrapper : wrappersArray) { + draw(*wrapper, texture); + } } batch->flush(); } @@ -181,15 +185,21 @@ void BlockWrapsRenderer::remove(u64id_t id) { if (found == wrappers.end()) { return; } - auto wrapper = std::move(found->second); + clearOrder(found->second.get()); wrappers.erase(id); +} +void BlockWrapsRenderer::clearOrder(const BlockWrapper* const wrapper) { auto it = renderOrder.begin(); while (it != renderOrder.end()) { - if (it->second == wrapper.get()) { + it->second.erase( + std::remove(it->second.begin(), it->second.end(), wrapper), + it->second.end() + ); + if (it->second.empty()) { it = renderOrder.erase(it); } else { ++it; } } -} +} \ No newline at end of file diff --git a/src/graphics/render/BlockWrapsRenderer.hpp b/src/graphics/render/BlockWrapsRenderer.hpp index f19bf6b66..632fe90cb 100644 --- a/src/graphics/render/BlockWrapsRenderer.hpp +++ b/src/graphics/render/BlockWrapsRenderer.hpp @@ -9,13 +9,9 @@ #include #include #include -#include -#include class Assets; -class Player; -class Level; -struct voxel; +class Content; class Chunks; class Texture; class DrawContext; @@ -36,24 +32,25 @@ struct BlockWrapper { class BlockWrapsRenderer { const Assets& assets; - const Level& level; + const Content& content; const Chunks& chunks; std::unique_ptr batch; - std::multimap renderOrder; + std::unordered_map> renderOrder; std::unordered_map> wrappers; u64id_t nextWrapper = 1; void draw(BlockWrapper& wrapper, const Texture* texture); void refreshWrapper(BlockWrapper& wrapper); + void clearOrder(const BlockWrapper* const wrapper); public: BlockWrapsRenderer( - const Assets& assets, const Level& level, const Chunks& chunks + const Assets& assets, const Content& content, const Chunks& chunks ); ~BlockWrapsRenderer(); - void draw(const DrawContext& ctx, const Player& player); + void draw(const DrawContext& ctx); u64id_t add( const glm::ivec3& position, diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 4157eeb98..e1f683b96 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -94,9 +94,9 @@ WorldRenderer::WorldRenderer( assets, level, *player.chunks, engine.getSettings().graphics )), texts(std::make_unique(*batch3d, assets, *frustumCulling)), - blockWraps( - std::make_unique(assets, level, *player.chunks) - ) { + blockWraps(std::make_unique( + assets, level.content, *player.chunks + )) { auto& settings = engine.getSettings(); level.events->listen( LevelEventType::CHUNK_HIDDEN, @@ -214,7 +214,7 @@ void WorldRenderer::renderOpaque( setupWorldShader(shader, camera, settings, fogFactor); chunksRenderer->drawChunks(camera, shader); - blockWraps->draw(ctx, player); + blockWraps->draw(ctx); int cloudsQuality = settings.graphics.cloudsQuality.get(); if (cloudsQuality > 0) { diff --git a/src/logic/scripting/lua/libs/libblockwraps.cpp b/src/logic/scripting/lua/libs/libblockwraps.cpp index 5b28f7dbb..084dd6b8b 100644 --- a/src/logic/scripting/lua/libs/libblockwraps.cpp +++ b/src/logic/scripting/lua/libs/libblockwraps.cpp @@ -34,10 +34,14 @@ static int l_set_pos(lua::State* L) { static int l_set_texture(lua::State* L) { if (auto wrapper = renderer->blockWraps->get(lua::tointeger(L, 1))) { + const char* newTexture = lua::require_string(L, 2); + for (int i = 0; i < wrapper->textureFaces.size(); i++) { - wrapper->textureFaces[i] = lua::require_string(L, 2); + if (wrapper->textureFaces[i] != newTexture) { + wrapper->textureFaces[i] = newTexture; + wrapper->dirtySides = 0xFF; + } } - wrapper->dirtySides = 0xFF; } return 0; } @@ -52,7 +56,7 @@ static int l_set_faces(lua::State* L) { wrapper->dirtySides |= (1 << i); } } else { - auto texture = lua::require_string(L, 2 + i);; + auto texture = lua::require_string(L, 2 + i); if ((wrapper->cullingBits & (1 << i)) == 0x0 || wrapper->textureFaces[i] != texture) { wrapper->cullingBits |= (1 << i); @@ -73,7 +77,6 @@ static int l_set_tints(lua::State* L) { wrapper->tints[i] = lua::tovec3(L, 2 + i); } } - wrapper->dirtySides = 0xFF; } return 0; } From 7f4878e2b69aec2ef9c9bae939e7f7630c8d1f62 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Mon, 16 Mar 2026 16:27:55 +0200 Subject: [PATCH 3/5] fix acoustics effects doesn't turn off --- src/audio/audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index e8fd96e14..cfc84ce00 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -190,6 +190,10 @@ void audio::initialize( audio::get_channel(channel.name)->setVolume(value * value); }, true)); } + objects_keeper.keepAlive(settings.acousticEffects.observe([=](auto value) { + if (value) return; + backend->setAcoustics(audio::Acoustics {}); + }, true)); if (inputEnabled) { ::input_device = backend->openInputDevice("", 44100, 1, 16); From 019fe68b48e4b7021eeec7f05f40929794c28021 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Mon, 16 Mar 2026 16:28:12 +0200 Subject: [PATCH 4/5] fix cmd reader blocking main thread --- src/devtools/stdin_cmd_reader.cpp | 8 +++++++- src/util/platform.cpp | 13 +++++++++++++ src/util/platform.hpp | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/devtools/stdin_cmd_reader.cpp b/src/devtools/stdin_cmd_reader.cpp index 8e4a48c22..90dc07e2b 100644 --- a/src/devtools/stdin_cmd_reader.cpp +++ b/src/devtools/stdin_cmd_reader.cpp @@ -4,6 +4,7 @@ #include "logic/CommandsInterpreter.hpp" #include "coders/json.hpp" #include "debug/Logger.hpp" +#include "util/platform.hpp" #include #include @@ -18,7 +19,12 @@ void cmd::start_stdin_cmd_reader(Engine& engine) { logger.info() << "reader thread started"; std::string line; - while (std::getline(std::cin, line)) { + while (true) { + if (!platform::stdin_has_data()) { + platform::sleep(10); + continue; + } + std::getline(std::cin, line); if (line.empty()) { continue; } diff --git a/src/util/platform.cpp b/src/util/platform.cpp index a7ba041db..f9ecf070d 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -14,8 +14,10 @@ #ifdef _WIN32 #include +#include #pragma comment(lib, "winmm.lib") #else +#include #include #endif @@ -290,3 +292,14 @@ void platform::new_engine_instance(const std::vector& args) { } #endif } + +bool platform::stdin_has_data() { +#ifdef _WIN32 + return _kbhit(); +#else + struct pollfd fds; + fds.fd = STDIN_FILENO; + fds.events = POLLIN; + return poll(&fds, 1, 0) == 1; +#endif +} \ No newline at end of file diff --git a/src/util/platform.hpp b/src/util/platform.hpp index 148c64c46..620178fc1 100644 --- a/src/util/platform.hpp +++ b/src/util/platform.hpp @@ -21,4 +21,6 @@ namespace platform { void new_engine_instance(const std::vector& args); /// @brief Open URL in web browser bool open_url(const std::string& url); + /// @brief Check if stdin has input + bool stdin_has_data(); } From 818a6bd6aea48d1cad2b3ebbfc9196e2ae7227a7 Mon Sep 17 00:00:00 2001 From: clasher113 Date: Mon, 16 Mar 2026 18:34:50 +0200 Subject: [PATCH 5/5] bring back multimap --- src/graphics/render/BlockWrapsRenderer.cpp | 24 +++++++++------------- src/graphics/render/BlockWrapsRenderer.hpp | 3 ++- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp index 0ed4157e4..fb72d3347 100644 --- a/src/graphics/render/BlockWrapsRenderer.cpp +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -102,10 +102,13 @@ void BlockWrapsRenderer::refreshWrapper(BlockWrapper& wrapper) { wrapper.texRegions[i] = texRegion; wrapper.uvRegions[i] = texRegion.region; - auto& wrappers = renderOrder[texRegion.texture]; - if (std::find(wrappers.begin(), wrappers.end(), &wrapper) == - wrappers.end()) { - wrappers.emplace_back(&wrapper); + auto range = renderOrder.equal_range(texRegion.texture); + auto it = + std::find_if(range.first, range.second, [&wrapper](auto& elem) { + return elem.second == &wrapper; + }); + if (it == range.second) { + renderOrder.emplace(texRegion.texture, &wrapper); } } wrapper.dirtySides = 0x0; @@ -147,12 +150,9 @@ void BlockWrapsRenderer::draw(const DrawContext& pctx) { refreshWrapper(*wrapper); } } - - for (const auto& [texture, wrappersArray] : renderOrder) { + for (const auto& [texture, wrapper] : renderOrder) { batch->setTexture(texture); - for (auto wrapper : wrappersArray) { - draw(*wrapper, texture); - } + draw(*wrapper, texture); } batch->flush(); } @@ -192,11 +192,7 @@ void BlockWrapsRenderer::remove(u64id_t id) { void BlockWrapsRenderer::clearOrder(const BlockWrapper* const wrapper) { auto it = renderOrder.begin(); while (it != renderOrder.end()) { - it->second.erase( - std::remove(it->second.begin(), it->second.end(), wrapper), - it->second.end() - ); - if (it->second.empty()) { + if (it->second == wrapper) { it = renderOrder.erase(it); } else { ++it; diff --git a/src/graphics/render/BlockWrapsRenderer.hpp b/src/graphics/render/BlockWrapsRenderer.hpp index 632fe90cb..0f2ed8f7e 100644 --- a/src/graphics/render/BlockWrapsRenderer.hpp +++ b/src/graphics/render/BlockWrapsRenderer.hpp @@ -9,6 +9,7 @@ #include #include #include +#include class Assets; class Content; @@ -36,7 +37,7 @@ class BlockWrapsRenderer { const Chunks& chunks; std::unique_ptr batch; - std::unordered_map> renderOrder; + std::multimap renderOrder; std::unordered_map> wrappers; u64id_t nextWrapper = 1;