Skip to content

Commit

Permalink
Blockwraps enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
NigthLier committed Dec 1, 2024
1 parent c668cda commit 296839b
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 28 deletions.
20 changes: 18 additions & 2 deletions doc/en/scripting/builtins/libgfx-blockwraps.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
20 changes: 18 additions & 2 deletions doc/ru/scripting/builtins/libgfx-blockwraps.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
использоваться для иных задач.

```lua
-- Создаёт обертку на указанной позиции, с указанной текстурой.
-- Создаёт обертку на указанной позиции, с указанной текстурой, удаляя существующую на позиции.
-- Возвращает id обёртки.
gfx.blockwraps.wrap(position: vec3, texture: str) --> int

Expand All @@ -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`.
Обертки удаляются автоматически при ломании/замене блока.
31 changes: 25 additions & 6 deletions src/graphics/render/BlockWrapsRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<MainBatch>(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<glm::ivec3*>(pos))) {
remove(existingId);
}
}
);
}

BlockWrapsRenderer::~BlockWrapsRenderer() = default;
Expand Down Expand Up @@ -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>(
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);
}
}
12 changes: 12 additions & 0 deletions src/graphics/render/BlockWrapsRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include <string>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <glm/glm.hpp>
#include <functional>

#include "MainBatch.hpp"
#include "typedefs.hpp"
Expand All @@ -12,6 +15,13 @@ class Player;
class Level;
class DrawContext;

template <>
struct std::hash<glm::ivec3> {
size_t operator()(const glm::ivec3& vec) const noexcept {
return std::hash<int>()(vec.x) ^ (std::hash<int>()(vec.y) << 1) ^ (std::hash<int>()(vec.z) << 2);
}
};

struct BlockWrapper {
glm::ivec3 position;
std::string texture;
Expand All @@ -23,6 +33,7 @@ class BlockWrapsRenderer {
std::unique_ptr<MainBatch> batch;

std::unordered_map<u64id_t, std::unique_ptr<BlockWrapper>> wrappers;
std::unordered_map<glm::ivec3, u64id_t> positionIndex;
u64id_t nextWrapper = 1;

void draw(const BlockWrapper& wrapper);
Expand All @@ -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);
};
2 changes: 1 addition & 1 deletion src/graphics/render/WorldRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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*>(chunk)); }
);
auto assets = engine->getAssets();
skybox = std::make_unique<Skybox>(
Expand Down
31 changes: 31 additions & 0 deletions src/logic/scripting/lua/libs/libblockwraps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<l_wrap>},
{"unwrap", lua::wrap<l_unwrap>},
{"set_pos", lua::wrap<l_set_pos>},
{"set_texture", lua::wrap<l_set_texture>},
{"get_pos", lua::wrap<l_get_pos>},
{"get_texture", lua::wrap<l_get_texture>},
{"is_alive", lua::wrap<l_is_alive>},
{"get_on_pos", lua::wrap<l_get_on_pos>},
{NULL, NULL}
};
3 changes: 3 additions & 0 deletions src/voxels/Chunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions src/world/Level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ Level::Level(
);
lighting = std::make_unique<Lighting>(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*>(chunk)->x, static_cast<Chunk*>(chunk)->z);
});

inventories = std::make_unique<Inventories>(*this);
Expand Down
14 changes: 6 additions & 8 deletions src/world/LevelEvents.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
12 changes: 5 additions & 7 deletions src/world/LevelEvents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
#include <unordered_map>
#include <vector>

class Chunk;

enum lvl_event_type {
EVT_CHUNK_HIDDEN,
EVT_BLOCK_SET,
};

using chunk_event_func = std::function<void(lvl_event_type, Chunk*)>;
using event_func = std::function<void(lvl_event_type, void*)>;

class LevelEvents {
std::unordered_map<lvl_event_type, std::vector<chunk_event_func>>
chunk_callbacks;
std::unordered_map<lvl_event_type, std::vector<event_func>> 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);
};

0 comments on commit 296839b

Please sign in to comment.