diff --git a/res/content/base/blocks/door.json b/res/content/base/blocks/door.json index 2cc23144..fd134355 100644 --- a/res/content/base/blocks/door.json +++ b/res/content/base/blocks/door.json @@ -11,7 +11,7 @@ "light-passing": true, "sky-light-passing": true, "size": [1, 2, 1], - "rotation": "pipe", + "rotation": "pane", "model": "aabb", - "hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2] + "hitbox": [0.0, 0.0, 0.0, 1.0, 2.0, 0.2] } diff --git a/res/content/base/preload.json b/res/content/base/preload.json new file mode 100644 index 00000000..801938a6 --- /dev/null +++ b/res/content/base/preload.json @@ -0,0 +1,6 @@ +{ + "sounds": [ + "blocks/door_open", + "blocks/door_close" + ] +} diff --git a/res/content/base/scripts/door.lua b/res/content/base/scripts/door.lua new file mode 100644 index 00000000..b922464d --- /dev/null +++ b/res/content/base/scripts/door.lua @@ -0,0 +1,13 @@ +function on_interact(x, y, z) + local inc = 1 + if block.get_user_bits(x, y, z, 0, 1) > 0 then + inc = 3 + block.set_user_bits(x, y, z, 0, 1, 0) + audio.play_sound("blocks/door_close", x+0.5, y+1, z+0.5, 1, 1) + else + block.set_user_bits(x, y, z, 0, 1, 1) + audio.play_sound("blocks/door_open", x+0.5, y+1, z+0.5, 1, 1) + end + block.set_rotation(x, y, z, (block.get_rotation(x, y, z) + inc) % 4) + return true +end diff --git a/res/content/base/sounds/blocks/door_close.ogg b/res/content/base/sounds/blocks/door_close.ogg new file mode 100644 index 00000000..53ead574 Binary files /dev/null and b/res/content/base/sounds/blocks/door_close.ogg differ diff --git a/res/content/base/sounds/blocks/door_open.ogg b/res/content/base/sounds/blocks/door_open.ogg new file mode 100644 index 00000000..77aadf80 Binary files /dev/null and b/res/content/base/sounds/blocks/door_open.ogg differ diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp index 22e76b84..680ace15 100644 --- a/src/logic/scripting/lua/libblock.cpp +++ b/src/logic/scripting/lua/libblock.cpp @@ -152,12 +152,7 @@ int l_set_block_rotation(lua_State* L) { lua_Integer y = lua_tointeger(L, 2); lua_Integer z = lua_tointeger(L, 3); lua_Integer value = lua_tointeger(L, 4); - voxel* vox = scripting::level->chunks->get(x, y, z); - if (vox == nullptr) { - return 0; - } - vox->state.rotation = value; - scripting::level->chunks->getChunkByVoxel(x, y, z)->setModifiedAndUnsaved(); + scripting::level->chunks->setRotation(x, y, z, value); return 0; } diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 9c09de7d..61c70058 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -200,6 +200,10 @@ void Chunks::eraseSegments(const Block* def, blockstate state, int x, int y, int } } +static constexpr uint8_t segment_to_int(int sx, int sy, int sz) { + return ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2)); +} + void Chunks::repairSegments(const Block* def, blockstate state, int x, int y, int z) { const auto& rotation = def->rotations.variants[state.rotation]; const auto id = def->rt.id; @@ -211,7 +215,7 @@ void Chunks::repairSegments(const Block* def, blockstate state, int x, int y, in continue; } blockstate segState = state; - segState.segment = ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2)); + segState.segment = segment_to_int(sx, sy, sz); glm::ivec3 pos(x, y, z); pos += rotation.axisX * sx; @@ -223,14 +227,14 @@ void Chunks::repairSegments(const Block* def, blockstate state, int x, int y, in } } -bool Chunks::checkReplaceability(const Block* def, blockstate state, glm::ivec3 origin) { +bool Chunks::checkReplaceability(const Block* def, blockstate state, glm::ivec3 origin, blockid_t ignore) { const auto& rotation = def->rotations.variants[state.rotation]; const auto size = def->size; for (int sy = 0; sy < size.y; sy++) { for (int sz = 0; sz < size.z; sz++) { for (int sx = 0; sx < size.x; sx++) { blockstate segState = state; - segState.segment = ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2)); + segState.segment = segment_to_int(sx, sy, sz); auto pos = origin; pos += rotation.axisX * sx; @@ -238,7 +242,7 @@ bool Chunks::checkReplaceability(const Block* def, blockstate state, glm::ivec3 pos += rotation.axisZ * sz; if (auto vox = get(pos.x, pos.y, pos.z)) { auto target = indices->getBlockDef(vox->id); - if (!target->replaceable) { + if (!target->replaceable && vox->id != ignore) { return false; } } else { @@ -250,6 +254,82 @@ bool Chunks::checkReplaceability(const Block* def, blockstate state, glm::ivec3 return true; } +void Chunks::setRotationExtended( + Block* def, blockstate state, glm::ivec3 origin, uint8_t index +) { + auto newstate = state; + newstate.rotation = index; + + // unable to rotate block (cause: obstacles) + if (!checkReplaceability(def, newstate, origin, def->rt.id)) { + return; + } + + const auto& rotation = def->rotations.variants[index]; + const auto size = def->size; + std::vector segmentBlocks; + + for (int sy = 0; sy < size.y; sy++) { + for (int sz = 0; sz < size.z; sz++) { + for (int sx = 0; sx < size.x; sx++) { + auto pos = origin; + pos += rotation.axisX * sx; + pos += rotation.axisY * sy; + pos += rotation.axisZ * sz; + + blockstate segState = newstate; + segState.segment = segment_to_int(sx, sy, sz); + + auto vox = get(pos); + // checked for nullptr by checkReplaceability + if (vox->id != def->rt.id) { + set(pos.x, pos.y, pos.z, def->rt.id, segState); + } else { + vox->state = segState; + auto chunk = getChunkByVoxel(pos.x, pos.y, pos.z); + chunk->setModifiedAndUnsaved(); + segmentBlocks.emplace_back(pos); + } + } + } + } + const auto& prevRotation = def->rotations.variants[state.rotation]; + for (int sy = 0; sy < size.y; sy++) { + for (int sz = 0; sz < size.z; sz++) { + for (int sx = 0; sx < size.x; sx++) { + auto pos = origin; + pos += prevRotation.axisX * sx; + pos += prevRotation.axisY * sy; + pos += prevRotation.axisZ * sz; + if (std::find(segmentBlocks.begin(), segmentBlocks.end(), pos) == segmentBlocks.end()) { + set(pos.x, pos.y, pos.z, 0, {}); + } + } + } + } +} + +void Chunks::setRotation(int32_t x, int32_t y, int32_t z, uint8_t index) { + if (index >= BlockRotProfile::MAX_COUNT) { + return; + } + auto vox = get(x, y, z); + if (vox == nullptr) { + return; + } + auto def = indices->getBlockDef(vox->id); + if (!def->rotatable || vox->state.rotation == index) { + return; + } + if (def->rt.extended) { + setRotationExtended(def, vox->state, {x, y, z}, index); + } else { + vox->state.rotation = index; + auto chunk = getChunkByVoxel(x, y, z); + chunk->setModifiedAndUnsaved(); + } +} + void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) { if (y < 0 || y >= CHUNK_H) { return; diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index fc2438c9..54b20b29 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -25,6 +25,7 @@ class Chunks { void eraseSegments(const Block* def, blockstate state, int x, int y, int z); void repairSegments(const Block* def, blockstate state, int x, int y, int z); + void setRotationExtended(Block* def, blockstate state, glm::ivec3 origin, uint8_t rotation); public: std::vector> chunks; std::vector> chunksSecond; @@ -40,7 +41,7 @@ public: WorldFiles* worldFiles, LevelEvents* events, const Content* content); ~Chunks() = default; - bool checkReplaceability(const Block* def, blockstate state, glm::ivec3 coord); + bool checkReplaceability(const Block* def, blockstate state, glm::ivec3 coord, blockid_t ignore=0); bool putChunk(const std::shared_ptr& chunk); Chunk* getChunk(int32_t x, int32_t z); @@ -55,6 +56,7 @@ public: ubyte getLight(int32_t x, int32_t y, int32_t z, int channel); void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state); glm::ivec3 seekOrigin(glm::ivec3 pos, const Block* def, blockstate state); + void setRotation(int32_t x, int32_t y, int32_t z, uint8_t rotation); voxel* rayCast( glm::vec3 start,