From 296839b132d79792578173d7254a03b9b52240d5 Mon Sep 17 00:00:00 2001 From: espektor Date: Mon, 2 Dec 2024 02:47:25 +0300 Subject: [PATCH] Blockwraps enhancements --- .../scripting/builtins/libgfx-blockwraps.md | 20 ++++++++++-- .../scripting/builtins/libgfx-blockwraps.md | 20 ++++++++++-- src/graphics/render/BlockWrapsRenderer.cpp | 31 +++++++++++++++---- src/graphics/render/BlockWrapsRenderer.hpp | 12 +++++++ src/graphics/render/WorldRenderer.cpp | 2 +- .../scripting/lua/libs/libblockwraps.cpp | 31 +++++++++++++++++++ src/voxels/Chunks.cpp | 3 ++ src/world/Level.cpp | 4 +-- src/world/LevelEvents.cpp | 14 ++++----- src/world/LevelEvents.hpp | 12 +++---- 10 files changed, 121 insertions(+), 28 deletions(-) diff --git a/doc/en/scripting/builtins/libgfx-blockwraps.md b/doc/en/scripting/builtins/libgfx-blockwraps.md index e03374dd7..4f9d42474 100644 --- a/doc/en/scripting/builtins/libgfx-blockwraps.md +++ b/doc/en/scripting/builtins/libgfx-blockwraps.md @@ -5,7 +5,7 @@ Library for working with *block wrappers*. Block wrappers are introduced to implement block destruction animation and can be used for other purposes. ```lua --- Creates a wrapper at the specified position, with the specified texture. +-- Creates a wrapper at the specified position, with the specified texture, removing the existing one at the position. -- Returns the wrapper id. gfx.blockwraps.wrap(position: vec3, texture: str) --> int @@ -17,6 +17,22 @@ gfx.blockwraps.set_pos(id: int, position: vec3) -- Changes the texture of the wrapper, if it exists. gfx.blockwraps.set_texture(id: int, texture: str) + +-- Gets the wrapper position if it exists. +-- Returns the wrapper position. +gfx.blockwraps.get_texture(id: int) + +-- Gets the texture of the wrapper, if it exists. +-- Returns the wrapper texture. +gfx.blockwraps.get_texture(id: int) + +-- Checks the existence of the wrapper. +-- Returns true/false depending on the wrapper existence. +gfx.blockwraps.is_alive(id: int) + +-- Searches for wrapper at the specified position. +-- Returns the wrapper id. +gfx.block wrap s.get_on_pos(position: vec3) ``` -Wrappers are not automatically removed without calling `unwrap`. +Wrappers are removed automatically when the block is broken/replaced. diff --git a/doc/ru/scripting/builtins/libgfx-blockwraps.md b/doc/ru/scripting/builtins/libgfx-blockwraps.md index ea794d2b5..584abfae1 100644 --- a/doc/ru/scripting/builtins/libgfx-blockwraps.md +++ b/doc/ru/scripting/builtins/libgfx-blockwraps.md @@ -6,7 +6,7 @@ использоваться для иных задач. ```lua --- Создаёт обертку на указанной позиции, с указанной текстурой. +-- Создаёт обертку на указанной позиции, с указанной текстурой, удаляя существующую на позиции. -- Возвращает id обёртки. gfx.blockwraps.wrap(position: vec3, texture: str) --> int @@ -18,6 +18,22 @@ gfx.blockwraps.set_pos(id: int, position: vec3) -- Меняет текстуру обёртки, если она существует. gfx.blockwraps.set_texture(id: int, texture: str) + +-- Получает позицию обёртки, если она существует. +-- Возвращает позицию обёртки. +gfx.blockwraps.get_texture(id: int) + +-- Получает текстуру обёртки, если она существует. +-- Возвращает текстуру обёртки. +gfx.blockwraps.get_texture(id: int) + +-- Проверяет существование обёртки. +-- Возвращает true/false в зависимости от существования обёртки. +gfx.blockwraps.is_alive(id: int) + +-- Ищет обёртку на указанной позиции. +-- Возвращает id обёртки. +gfx.blockwraps.get_on_pos(position: vec3) ``` -Обертки не удаляются автоматически без вызова `unwrap`. +Обертки удаляются автоматически при ломании/замене блока. diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp index 3ad30ad85..247010c0b 100644 --- a/src/graphics/render/BlockWrapsRenderer.cpp +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -13,9 +13,18 @@ #include "voxels/Chunks.hpp" #include "window/Window.hpp" #include "world/Level.hpp" +#include "world/LevelEvents.hpp" BlockWrapsRenderer::BlockWrapsRenderer(const Assets& assets, const Level& level) : assets(assets), level(level), batch(std::make_unique(1024)) { + this->level.events->listen( + EVT_BLOCK_SET, + [this](lvl_event_type, void* pos) { + if (const u64id_t existingId = get_id_by_pos(*static_cast(pos))) { + remove(existingId); + } + } + ); } BlockWrapsRenderer::~BlockWrapsRenderer() = default; @@ -88,21 +97,31 @@ void BlockWrapsRenderer::draw(const DrawContext& pctx, const Player& player) { u64id_t BlockWrapsRenderer::add( const glm::ivec3& position, const std::string& texture ) { + if (const u64id_t existingId = get_id_by_pos(position)) { + remove(existingId); + } + u64id_t id = nextWrapper++; wrappers[id] = std::make_unique( BlockWrapper {position, texture} ); + positionIndex[position] = id; return id; } BlockWrapper* BlockWrapsRenderer::get(u64id_t id) const { const auto& found = wrappers.find(id); - if (found == wrappers.end()) { - return nullptr; - } - return found->second.get(); + return (found != wrappers.end()) ? found->second.get() : nullptr; } -void BlockWrapsRenderer::remove(u64id_t id) { - wrappers.erase(id); +u64id_t BlockWrapsRenderer::get_id_by_pos(const glm::ivec3& position) const { + const auto& found = positionIndex.find(position); + return (found != positionIndex.end()) ? found->second : 0; } + +void BlockWrapsRenderer::remove(u64id_t id) { + if (const auto& found = wrappers.find(id); found != wrappers.end()) { + positionIndex.erase(found->second->position); + wrappers.erase(found); + } +} \ No newline at end of file diff --git a/src/graphics/render/BlockWrapsRenderer.hpp b/src/graphics/render/BlockWrapsRenderer.hpp index 728e664a7..ef5ac8c84 100644 --- a/src/graphics/render/BlockWrapsRenderer.hpp +++ b/src/graphics/render/BlockWrapsRenderer.hpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "MainBatch.hpp" #include "typedefs.hpp" @@ -12,6 +15,13 @@ class Player; class Level; class DrawContext; +template <> +struct std::hash { + size_t operator()(const glm::ivec3& vec) const noexcept { + return std::hash()(vec.x) ^ (std::hash()(vec.y) << 1) ^ (std::hash()(vec.z) << 2); + } +}; + struct BlockWrapper { glm::ivec3 position; std::string texture; @@ -23,6 +33,7 @@ class BlockWrapsRenderer { std::unique_ptr batch; std::unordered_map> wrappers; + std::unordered_map positionIndex; u64id_t nextWrapper = 1; void draw(const BlockWrapper& wrapper); @@ -35,6 +46,7 @@ class BlockWrapsRenderer { u64id_t add(const glm::ivec3& position, const std::string& texture); BlockWrapper* get(u64id_t id) const; + u64id_t get_id_by_pos(const glm::ivec3& position) const; void remove(u64id_t id); }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 19d6d232f..e81509455 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -86,7 +86,7 @@ WorldRenderer::WorldRenderer( auto& settings = engine->getSettings(); level.events->listen( EVT_CHUNK_HIDDEN, - [this](lvl_event_type, Chunk* chunk) { chunks->unload(chunk); } + [this](lvl_event_type, void* chunk) { chunks->unload(static_cast(chunk)); } ); auto assets = engine->getAssets(); skybox = std::make_unique( diff --git a/src/logic/scripting/lua/libs/libblockwraps.cpp b/src/logic/scripting/lua/libs/libblockwraps.cpp index fec1c5d7a..35bb64734 100644 --- a/src/logic/scripting/lua/libs/libblockwraps.cpp +++ b/src/logic/scripting/lua/libs/libblockwraps.cpp @@ -34,10 +34,41 @@ static int l_set_texture(lua::State* L) { return 0; } +static int l_get_pos(lua::State* L) { + if (const auto wrapper = renderer->blockWraps->get(lua::tointeger(L, 1))) { + return lua::pushvec3(L, wrapper->position); + } + return 0; +} + +static int l_get_texture(lua::State* L) { + if (const auto wrapper = renderer->blockWraps->get(lua::tointeger(L, 1))) { + return lua::pushstring(L, wrapper->texture); + } + return 0; +} + +static int l_is_alive(lua::State* L) { + return lua::pushboolean( + L, renderer->blockWraps->get(lua::tointeger(L, 1)) != nullptr + ); +} + +static int l_get_on_pos(lua::State* L) { + if (const auto id = renderer->blockWraps->get_id_by_pos(lua::tovec3(L, 1))) { + return lua::pushinteger(L, id); + } + return 0; +} + const luaL_Reg blockwrapslib[] = { {"wrap", lua::wrap}, {"unwrap", lua::wrap}, {"set_pos", lua::wrap}, {"set_texture", lua::wrap}, + {"get_pos", lua::wrap}, + {"get_texture", lua::wrap}, + {"is_alive", lua::wrap}, + {"get_on_pos", lua::wrap}, {NULL, NULL} }; diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 0942550e4..659c2667a 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -428,6 +428,9 @@ void Chunks::set( if (lz == CHUNK_D - 1 && (chunk = getChunk(cx, cz + 1))) { chunk->flags.modified = true; } + + glm::ivec3 pos(x, y, z); + level->events->trigger(EVT_BLOCK_SET, &pos); } voxel* Chunks::rayCast( diff --git a/src/world/Level.cpp b/src/world/Level.cpp index ed370d084..4fae20b16 100644 --- a/src/world/Level.cpp +++ b/src/world/Level.cpp @@ -62,8 +62,8 @@ Level::Level( ); lighting = std::make_unique(content, chunks.get()); - events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type, Chunk* chunk) { - this->chunksStorage->remove(chunk->x, chunk->z); + events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type, void* chunk) { + this->chunksStorage->remove(static_cast(chunk)->x, static_cast(chunk)->z); }); inventories = std::make_unique(*this); diff --git a/src/world/LevelEvents.cpp b/src/world/LevelEvents.cpp index 00017cc66..7edecf5d2 100644 --- a/src/world/LevelEvents.cpp +++ b/src/world/LevelEvents.cpp @@ -1,17 +1,15 @@ #include "LevelEvents.hpp" -#include "voxels/Chunk.hpp" - using std::vector; -void LevelEvents::listen(lvl_event_type type, const chunk_event_func& func) { - auto& callbacks = chunk_callbacks[type]; +void LevelEvents::listen(lvl_event_type type, const event_func& func) { + auto& callbacks = this->callbacks[type]; callbacks.push_back(func); } -void LevelEvents::trigger(lvl_event_type type, Chunk* chunk) { - const auto& callbacks = chunk_callbacks[type]; - for (const chunk_event_func& func : callbacks) { - func(type, chunk); +void LevelEvents::trigger(lvl_event_type type, void* data) { + const auto& callbacks = this->callbacks[type]; + for (const event_func& func : callbacks) { + func(type, data); } } diff --git a/src/world/LevelEvents.hpp b/src/world/LevelEvents.hpp index d0518b5ca..518dcc0b0 100644 --- a/src/world/LevelEvents.hpp +++ b/src/world/LevelEvents.hpp @@ -4,18 +4,16 @@ #include #include -class Chunk; - enum lvl_event_type { EVT_CHUNK_HIDDEN, + EVT_BLOCK_SET, }; -using chunk_event_func = std::function; +using event_func = std::function; class LevelEvents { - std::unordered_map> - chunk_callbacks; + std::unordered_map> callbacks; public: - void listen(lvl_event_type type, const chunk_event_func& func); - void trigger(lvl_event_type type, Chunk* chunk); + void listen(lvl_event_type type, const event_func& func); + void trigger(lvl_event_type type, void* data); };