Door block added.

This commit is contained in:
Quentin Bazin 2020-03-29 19:19:39 +02:00
parent c3eaa06653
commit 2ecef2ded9
25 changed files with 187 additions and 18 deletions

View File

@ -233,6 +233,13 @@ Parameters:
- `screen_height` (`u16`): height of the screen
- `gui_scale` (`u8`): current scaling setting
### `on_block_destroyed`
Parameters:
- `pos` (`ivec3`): position of the block
- `world` (`World`): instance of `ServerWorld`
### `on_block_placed`
Parameters:

View File

@ -23,6 +23,8 @@
- `void set_string(string attribute, string value)`
- `int get_int(string attribute)`
- `void set_int(string attribute, int value)`
- `bool get_bool(string attribute)`
- `void set_bool(string attribute, bool value)`
## Chunk

View File

@ -132,9 +132,6 @@ mod:block {
is_light_source = true
}
dofile("mods/default/workbench.lua")
dofile("mods/default/furnace.lua")
mod:block {
id = "iron_ore",
name = "Iron Ore",
@ -315,3 +312,7 @@ mod:block {
end
}
dofile("mods/default/blocks/workbench.lua")
dofile("mods/default/blocks/furnace.lua")
dofile("mods/default/blocks/door.lua")

View File

@ -0,0 +1,112 @@
--
-- =====================================================================================
--
-- OpenMiner
--
-- Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
-- Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
--
-- This file is part of OpenMiner.
--
-- OpenMiner is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
--
-- OpenMiner is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public License
-- along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--
-- =====================================================================================
--
function open_door(pos, world)
local data = world:get_block_data(pos.x, pos.y, pos.z)
if not data then return end
-- FIXME: Add a helper to get rotation from data
local rotation = world:get_data(pos.x, pos.y, pos.z)
local is_opened = data.meta:get_bool("is_opened") or false
if not is_opened then
world:set_data(pos.x, pos.y, pos.z, (rotation - 1) % 4)
else
world:set_data(pos.x, pos.y, pos.z, (rotation + 1) % 4)
end
data.meta:set_bool("is_opened", not is_opened)
end
mod:block {
id = "door_wood_upper",
name = "Wooden Door",
tiles = "door_wood_upper.png",
inventory_image = "door_wood.png",
groups = {ci_ignore = 1},
is_rotatable = true,
is_opaque = false,
draw_type = "boundingbox",
bounding_box = {13 / 16, 0, 0, 3 / 16, 1, 1},
on_block_placed = function(pos, world)
world:add_block_data(pos.x, pos.y, pos.z, 0, 0)
end,
on_block_destroyed = function(pos, world)
local lower_block_id = openminer:registry():get_block_from_string("default:door_wood_lower"):id()
if world:get_block(pos.x, pos.y, pos.z - 1) == lower_block_id then
world:set_block(pos.x, pos.y, pos.z - 1, 0)
end
end,
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
open_door(pos, world)
open_door({x = pos.x, y = pos.y, z = pos.z - 1}, world)
end
}
mod:block {
id = "door_wood_lower",
name = "Wooden Door",
tiles = "door_wood_lower.png",
inventory_image = "door_wood.png",
is_rotatable = true,
is_opaque = false,
draw_type = "boundingbox",
bounding_box = {13 / 16, 0, 0, 3 / 16, 1, 1},
on_block_placed = function(pos, world)
world:add_block_data(pos.x, pos.y, pos.z, 0, 0)
if world:get_block(pos.x, pos.y, pos.z + 1) == 0 then
local data = world:get_data(pos.x, pos.y, pos.z)
world:set_data(pos.x, pos.y, pos.z + 1, data)
local upper_block_id = openminer:registry():get_block_from_string("default:door_wood_upper"):id()
world:set_block(pos.x, pos.y, pos.z + 1, upper_block_id)
end
end,
on_block_destroyed = function(pos, world)
local upper_block_id = openminer:registry():get_block_from_string("default:door_wood_upper"):id()
if world:get_block(pos.x, pos.y, pos.z + 1) == upper_block_id then
world:set_block(pos.x, pos.y, pos.z + 1, 0)
end
end,
on_block_activated = function(pos, player, world, client, server, screen_width, screen_height, gui_scale)
open_door(pos, world)
open_door({x = pos.x, y = pos.y, z = pos.z + 1}, world)
end
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

View File

@ -42,7 +42,7 @@ ItemWidget::ItemWidget(Inventory &inventory, u16 x, u16 y, Widget *parent)
void ItemWidget::update() {
if (stack().item().isBlock()) {
const Block &block = Registry::getInstance().getBlock(stack().item().id());
if (block.drawType() != BlockDrawType::XShape) {
if (block.drawType() != BlockDrawType::XShape && block.inventoryImage().empty()) {
m_cube.updateVertexBuffer(block);
m_isImage = false;
}

View File

@ -91,8 +91,6 @@ void BlockCursor::onEvent(const SDL_Event &event, const Hotbar &hotbar) {
gk::FloatBox boundingBox = newBlock.boundingBox() + gk::Vector3f(x - m_player.x(), y - m_player.y(), z - m_player.z());
gk::FloatBox playerBoundingBox = m_player.hitbox();
if (!boundingBox.intersects(playerBoundingBox)) {
m_world.setBlock(x, y, z, hotbar.currentItem());
u32 block = hotbar.currentItem();
if (newBlock.isRotatable()) {
u16 data = m_player.getOppositeDirection() & 0x3;
@ -101,6 +99,8 @@ void BlockCursor::onEvent(const SDL_Event &event, const Hotbar &hotbar) {
block |= data << 16;
}
m_world.setBlock(x, y, z, hotbar.currentItem());
m_client.sendPlayerPlaceBlock(x, y, z, block);
const ItemStack &currentStack = m_player.inventory().getStack(hotbar.cursorPos(), 0);

View File

@ -36,6 +36,10 @@ void BlockMetadata::setInt(const std::string &name, int value) {
m_data[name].set(value, BlockMetadataValue::Type::Int);
}
void BlockMetadata::setBool(const std::string &name, bool value) {
m_data[name].set(value, BlockMetadataValue::Type::Bool);
}
void BlockMetadata::serialize(sf::Packet &packet) const {
packet << u32(m_data.size());
for (auto &it : m_data) {
@ -46,6 +50,9 @@ void BlockMetadata::serialize(sf::Packet &packet) const {
else if (it.second.type() == BlockMetadataValue::Type::Int) {
packet << it.second.get<int>();
}
else if (it.second.type() == BlockMetadataValue::Type::Bool) {
packet << it.second.get<bool>();
}
}
}
@ -68,6 +75,11 @@ void BlockMetadata::deserialize(sf::Packet &packet) {
packet >> value;
m_data[name].set(value, type);
}
else if (type == BlockMetadataValue::Type::Bool) {
bool value;
packet >> value;
m_data[name].set(value, type);
}
}
}

View File

@ -43,7 +43,8 @@ class BlockMetadataValue {
enum class Type : u8 {
Undefined,
String,
Int
Int,
Bool
};
template<typename T>
@ -68,6 +69,7 @@ class BlockMetadata : public ISerializable {
public:
void setString(const std::string &name, const std::string &value);
void setInt(const std::string &name, int value);
void setBool(const std::string &name, bool value);
template<typename T>
T &get(const std::string &name) {

View File

@ -68,7 +68,7 @@ void Chunk::setBlock(int x, int y, int z, u16 type) {
if(z < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setBlock(x, y, z + Chunk::height, type); return; }
if(z >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setBlock(x, y, z - Chunk::height, type); return; }
if (m_data[z][y][x] == type) return;
if ((m_data[z][y][x] & 0xffff) == type) return;
const Block &block = Registry::getInstance().getBlock(type);
if (block.canUpdate()) {
@ -89,6 +89,11 @@ void Chunk::setBlock(int x, int y, int z, u16 type) {
onBlockPlaced(x, y, z, block);
if (m_data[z][y][x] != 0) {
const Block &oldBlock = Registry::getInstance().getBlock(m_data[z][y][x]);
onBlockDestroyed(x, y, z, oldBlock);
}
setBlockRaw(x, y, z, type);
if(x == 0 && m_surroundingChunks[West]) { m_surroundingChunks[West]->m_hasChanged = true; }
@ -121,7 +126,7 @@ void Chunk::setBlockRaw(int x, int y, int z, u16 type) {
if(z < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setBlockRaw(x, y, z + Chunk::height, type); return; }
if(z >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setBlockRaw(x, y, z - Chunk::height, type); return; }
if (m_data[z][y][x] == type) return;
if ((m_data[z][y][x] & 0xffff) == type) return;
if (type == 0) {
auto it = m_blockData.find(gk::Vector3i{x, y, z});
@ -129,7 +134,8 @@ void Chunk::setBlockRaw(int x, int y, int z, u16 type) {
m_blockData.erase(it);
}
m_data[z][y][x] = type;
m_data[z][y][x] &= 0xffff0000;
m_data[z][y][x] |= type;
m_hasChanged = true;
}

View File

@ -66,6 +66,7 @@ class Chunk : public gk::NonCopyable {
void setBlockRaw(int x, int y, int z, u16 block);
virtual void onBlockPlaced(int, int, int, const Block &) const {}
virtual void onBlockDestroyed(int, int, int, const Block &) const {}
BlockData *getBlockData(int x, int y, int z) const;
BlockData *addBlockData(int x, int y, int z, int inventoryWidth = 0, int inventoryHeight = 0);

View File

@ -168,7 +168,10 @@ void ScriptEngine::initUsertypes() {
"set_string", &BlockMetadata::setString,
"get_int", &BlockMetadata::getLuaObject<int>,
"set_int", &BlockMetadata::setInt
"set_int", &BlockMetadata::setInt,
"get_bool", &BlockMetadata::getLuaObject<bool>,
"set_bool", &BlockMetadata::setBool
);
m_lua.new_usertype<ClientInfo>("ClientInfo",

View File

@ -67,6 +67,7 @@ inline void LuaBlockLoader::loadProperties(ServerBlock &block, const sol::table
block.setOnBlockActivated(table["on_block_activated"]);
block.setOnTick(table["on_tick"]);
block.setOnBlockPlaced(table["on_block_placed"]);
block.setOnBlockDestroyed(table["on_block_destroyed"]);
block.setRotatable(table["is_rotatable"].get_or(false));
block.setInventoryImage(table["inventory_image"].get_or<std::string>(""));
}

View File

@ -162,8 +162,8 @@ void ServerCommandHandler::setupCallbacks() {
packet >> x >> y >> z >> block;
ServerWorld &world = getWorldForClient(client.id);
world.setBlock(x, y, z, block & 0xffff);
world.setData(x, y, z, block >> 16);
world.setBlock(x, y, z, block & 0xffff);
m_scriptEngine.luaCore().onEvent(LuaEventType::OnBlockPlaced, glm::ivec3{x, y, z}, m_players.at(client.id), world, client, *this);

View File

@ -80,3 +80,14 @@ void ServerBlock::onBlockPlaced(const glm::ivec3 &pos, World &world) const {
}
}
void ServerBlock::onBlockDestroyed(const glm::ivec3 &pos, World &world) const {
try {
if (m_onBlockDestroyed) {
m_onBlockDestroyed(pos, world);
}
}
catch (const sol::error &e) {
std::cerr << e.what() << std::endl;
}
}

View File

@ -41,17 +41,21 @@ class ServerBlock : public Block {
void onTick(const glm::ivec3 &, Chunk &, World &, ServerCommandHandler &) const;
bool onBlockActivated(const glm::ivec3 &pos, Player &player, World &world, ClientInfo &client, ServerCommandHandler &server, u16 screenWidth, u16 screenHeight, u8 guiScale) const;
void onBlockPlaced(const glm::ivec3 &pos, World &world) const;
void onBlockDestroyed(const glm::ivec3 &pos, World &world) const;
bool canUpdate() const { return m_onTick.valid(); }
void setOnBlockActivated(const sol::function &function) { m_onBlockActivated = function; m_canBeActivated = m_onBlockActivated.valid(); }
void setOnTick(const sol::function &function) { m_onTick = function; m_canUpdate = m_onTick.valid(); }
void setOnBlockPlaced(const sol::function &function) { m_onBlockPlaced = function; }
void setOnBlockActivated(const sol::protected_function &function) { m_onBlockActivated = function; m_canBeActivated = m_onBlockActivated.valid(); }
void setOnTick(const sol::protected_function &function) { m_onTick = function; m_canUpdate = m_onTick.valid(); }
void setOnBlockPlaced(const sol::protected_function &function) { m_onBlockPlaced = function; }
void setOnBlockDestroyed(const sol::protected_function &function) { m_onBlockDestroyed = function; }
private:
sol::unsafe_function m_onBlockActivated;
sol::unsafe_function m_onTick;
sol::unsafe_function m_onBlockPlaced;
sol::protected_function m_onBlockActivated;
sol::protected_function m_onTick;
sol::protected_function m_onBlockPlaced;
sol::protected_function m_onBlockDestroyed;
mutable bool m_onTickEnabled = true;
};

View File

@ -42,6 +42,11 @@ void ServerChunk::onBlockPlaced(int x, int y, int z, const Block &block) const {
serverBlock.onBlockPlaced(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, m_world);
}
void ServerChunk::onBlockDestroyed(int x, int y, int z, const Block &block) const {
const ServerBlock &serverBlock = (ServerBlock &)block;
serverBlock.onBlockDestroyed(glm::ivec3{x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH, z + m_z * CHUNK_HEIGHT}, m_world);
}
void ServerChunk::tick(World &world, ServerCommandHandler &server) {
if (!m_tickingBlocks.empty()) {
for (auto &it : m_tickingBlocks) {

View File

@ -43,6 +43,8 @@ class ServerChunk : public Chunk {
void updateLights();
void onBlockPlaced(int x, int y, int z, const Block &block) const;
void onBlockDestroyed(int x, int y, int z, const Block &block) const;
void tick(World &world, ServerCommandHandler &server);
bool isSent() const { return m_isSent; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B