From abbabe892436900229eb1cd9f7ba7a499a9d640d Mon Sep 17 00:00:00 2001 From: Quentin Bazin Date: Sat, 8 Feb 2020 17:45:20 +0900 Subject: [PATCH] [BlockMetadata] Added. Now used in FurnaceWidget and furnace.lua --- README.md | 2 +- TODO | 2 +- client/source/gui/FurnaceWidget.cpp | 6 +- .../source/network/ClientCommandHandler.cpp | 2 +- common/include/world/BlockData.hpp | 3 +- common/include/world/BlockMetadata.hpp | 86 ++++++ common/source/world/BlockMetadata.cpp | 60 +++++ mods/default/bit.lua | 247 ------------------ mods/default/furnace.lua | 12 +- mods/default/init.lua | 1 - server/source/lua/ScriptEngine.cpp | 11 +- .../source/network/ServerCommandHandler.cpp | 2 +- server/source/world/ServerBlock.cpp | 2 +- server/source/world/ServerWorld.cpp | 2 +- 14 files changed, 173 insertions(+), 265 deletions(-) create mode 100644 common/include/world/BlockMetadata.hpp create mode 100644 common/source/world/BlockMetadata.cpp delete mode 100644 mods/default/bit.lua diff --git a/README.md b/README.md index 9d3b3918f..63846c34f 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,12 @@ This list is non exhaustive. - Block/item/recipe definition - Custom GUI creation - Special blocks (workbench, furnace) +- Block metadata ### Missing features - Texture pack system - World loading/saving -- Advanced block metadata - Particle system - Fluid propagation - Player model display (currently displaying an ugly box) diff --git a/TODO b/TODO index 853b41f3e..3c86d1ec2 100644 --- a/TODO +++ b/TODO @@ -82,7 +82,7 @@ TODO # World -• TODO: Block metadata +• DONE: Block metadata • TODO: Day/night cycle # Chunk generation diff --git a/client/source/gui/FurnaceWidget.cpp b/client/source/gui/FurnaceWidget.cpp index f20f7b525..35515c80b 100644 --- a/client/source/gui/FurnaceWidget.cpp +++ b/client/source/gui/FurnaceWidget.cpp @@ -48,9 +48,9 @@ void FurnaceWidget::onEvent(const SDL_Event &event) { } void FurnaceWidget::update() { - u16 ticksRemaining = m_blockData.data & 0xfff; - u16 currentBurnTime = (m_blockData.data >> 12) & 0xfff; - u16 itemProgress = (m_blockData.data >> 24) & 0xff; + u16 ticksRemaining = m_blockData.meta.get("ticks_remaining"); + u16 currentBurnTime = m_blockData.meta.get("current_burn_time"); + u16 itemProgress = m_blockData.meta.get("item_progress"); if (currentBurnTime) { m_burnImage.setPosition(57, 37 + 14 - ticksRemaining * 14 / currentBurnTime, 0); diff --git a/client/source/network/ClientCommandHandler.cpp b/client/source/network/ClientCommandHandler.cpp index f6dbbfb33..63d8419fa 100644 --- a/client/source/network/ClientCommandHandler.cpp +++ b/client/source/network/ClientCommandHandler.cpp @@ -170,7 +170,7 @@ void ClientCommandHandler::setupCallbacks() { if (data) { bool useAltTiles; - packet >> data->data >> useAltTiles; + packet >> data->meta >> useAltTiles; if (data->useAltTiles != useAltTiles) { chunk->setChanged(true); diff --git a/common/include/world/BlockData.hpp b/common/include/world/BlockData.hpp index 78aeff1c1..cb0b67ac6 100644 --- a/common/include/world/BlockData.hpp +++ b/common/include/world/BlockData.hpp @@ -14,6 +14,7 @@ #ifndef BLOCKDATA_HPP_ #define BLOCKDATA_HPP_ +#include "BlockMetadata.hpp" #include "Inventory.hpp" struct BlockData { @@ -24,7 +25,7 @@ struct BlockData { Inventory inventory; - u32 data = 0; + BlockMetadata meta; bool useAltTiles = false; }; diff --git a/common/include/world/BlockMetadata.hpp b/common/include/world/BlockMetadata.hpp new file mode 100644 index 000000000..7c347ee3a --- /dev/null +++ b/common/include/world/BlockMetadata.hpp @@ -0,0 +1,86 @@ +/* + * ===================================================================================== + * + * Filename: BlockMetadata.hpp + * + * Description: + * + * Created: 08/02/2020 16:02:50 + * + * Author: Quentin Bazin, + * + * ===================================================================================== + */ +#ifndef BLOCKMETADATA_HPP_ +#define BLOCKMETADATA_HPP_ + +#include +#include +#include + +#include + +#include +#include + +#include "ISerializable.hpp" + +class BlockMetadataValue { + public: + enum class Type : u8 { + Undefined, + String, + Int + }; + + template + T &get() const { + return *std::static_pointer_cast(m_value); + } + + template + void set(const T &value, Type type) { + m_value = std::make_shared(value); + m_type = type; + } + + Type type() const { return m_type; } + + private: + std::shared_ptr m_value; + Type m_type = Type::Undefined; +}; + +class BlockMetadata : public ISerializable { + public: + void setString(const std::string &name, const std::string &value); + void setInt(const std::string &name, int value); + + template + T &get(const std::string &name) { + auto it = m_data.find(name); + if (it == m_data.end()) + throw EXCEPTION("Unable to find metadata named", name); + + return it->second.get(); + } + + template + sol::object getLuaObject(const std::string &name, sol::this_state state) { + sol::state_view lua{state}; + + auto it = m_data.find(name); + if (it == m_data.end()) + return sol::make_object(lua, sol::lua_nil); + + return sol::make_object(lua, it->second.get()); + } + + void serialize(sf::Packet &packet) const override; + void deserialize(sf::Packet &packet) override; + + private: + std::unordered_map m_data; +}; + +#endif // BLOCKMETADATA_HPP_ diff --git a/common/source/world/BlockMetadata.cpp b/common/source/world/BlockMetadata.cpp new file mode 100644 index 000000000..eeba2a089 --- /dev/null +++ b/common/source/world/BlockMetadata.cpp @@ -0,0 +1,60 @@ +/* + * ===================================================================================== + * + * Filename: BlockMetadata.cpp + * + * Description: + * + * Created: 08/02/2020 16:03:18 + * + * Author: Quentin Bazin, + * + * ===================================================================================== + */ +#include + +#include "BlockMetadata.hpp" + +void BlockMetadata::setString(const std::string &name, const std::string &value) { + m_data[name].set(value, BlockMetadataValue::Type::String); +} + +void BlockMetadata::setInt(const std::string &name, int value) { + m_data[name].set(value, BlockMetadataValue::Type::Int); +} + +void BlockMetadata::serialize(sf::Packet &packet) const { + packet << u32(m_data.size()); + for (auto &it : m_data) { + packet << u8(it.second.type()) << it.first; + if (it.second.type() == BlockMetadataValue::Type::String) { + packet << it.second.get(); + } + else if (it.second.type() == BlockMetadataValue::Type::Int) { + packet << it.second.get(); + } + } +} + +void BlockMetadata::deserialize(sf::Packet &packet) { + u32 size; + packet >> size; + for (u32 i = 0 ; i < size ; ++i) { + u8 typeU8; + std::string name; + packet >> typeU8 >> name; + + BlockMetadataValue::Type type = BlockMetadataValue::Type(typeU8); + if (type == BlockMetadataValue::Type::String) { + std::string value; + packet >> value; + m_data[name].set(value, type); + } + else if (type == BlockMetadataValue::Type::Int) { + int value; + packet >> value; + m_data[name].set(value, type); + } + } +} + diff --git a/mods/default/bit.lua b/mods/default/bit.lua deleted file mode 100644 index 5abae0c03..000000000 --- a/mods/default/bit.lua +++ /dev/null @@ -1,247 +0,0 @@ ---[[--------------- -LuaBit v0.4 -------------------- -a bitwise operation lib for lua. - -http://luaforge.net/projects/bit/ - -How to use: -------------------- - bit.bnot(n) -- bitwise not (~n) - bit.band(m, n) -- bitwise and (m & n) - bit.bor(m, n) -- bitwise or (m | n) - bit.bxor(m, n) -- bitwise xor (m ^ n) - bit.brshift(n, bits) -- right shift (n >> bits) - bit.blshift(n, bits) -- left shift (n << bits) - bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>) - -Please note that bit.brshift and bit.blshift only support number within -32 bits. - -2 utility functions are provided too: - bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence) - -- high bits first - bit.tonumb(bit_tbl) -- convert a bit table into a number -------------------- - -Under the MIT license. - -copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com) ---]]--------------- - -do - ------------------------- --- bit lib implementions - -local function check_int(n) - -- checking not float - if not n or (n - math.floor(n) > 0) then - error("trying to use bitwise operation on non-integer!") - end -end - -local function to_bits(n) - check_int(n) - if(n < 0) then - -- negative - return to_bits(bit.bnot(math.abs(n)) + 1) - end - -- to bits table - local tbl = {} - local cnt = 1 - while (n > 0) do - local last = n % 2 - if(last == 1) then - tbl[cnt] = 1 - else - tbl[cnt] = 0 - end - n = (n-last)/2 - cnt = cnt + 1 - end - - return tbl -end - -local function tbl_to_number(tbl) - local n = #tbl - - local rslt = 0 - local power = 1 - for i = 1, n do - rslt = rslt + tbl[i]*power - power = power*2 - end - - return rslt -end - -local function expand(tbl_m, tbl_n) - local big = {} - local small = {} - if(#tbl_m > #tbl_n) then - big = tbl_m - small = tbl_n - else - big = tbl_n - small = tbl_m - end - -- expand small - for i = #small + 1, #big do - small[i] = 0 - end - -end - -local function bit_or(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = math.max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i]== 0 and tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl_to_number(tbl) -end - -local function bit_and(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = math.max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i]== 0 or tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl_to_number(tbl) -end - -local function bit_not(n) - - local tbl = to_bits(n) - local size = math.max(#tbl, 32) - for i = 1, size do - if(tbl[i] == 1) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - return tbl_to_number(tbl) -end - -local function bit_xor(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = math.max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i] ~= tbl_n[i]) then - tbl[i] = 1 - else - tbl[i] = 0 - end - end - - --table.foreach(tbl, print) - - return tbl_to_number(tbl) -end - -local function bit_rshift(n, bits) - check_int(n) - - local high_bit = 0 - if(n < 0) then - -- negative - n = bit_not(math.abs(n)) + 1 - high_bit = 2147483648 -- 0x80000000 - end - - for i=1, bits do - n = n/2 - n = bit_or(math.floor(n), high_bit) - end - return math.floor(n) -end - --- logic rightshift assures zero filling shift -local function bit_logic_rshift(n, bits) - check_int(n) - if(n < 0) then - -- negative - n = bit_not(math.abs(n)) + 1 - end - for i=1, bits do - n = n/2 - end - return math.floor(n) -end - -local function bit_lshift(n, bits) - check_int(n) - - if(n < 0) then - -- negative - n = bit_not(math.abs(n)) + 1 - end - - for i=1, bits do - n = n*2 - end - return bit_and(n, 4294967295) -- 0xFFFFFFFF -end - -local function bit_xor2(m, n) - local rhs = bit_or(bit_not(m), bit_not(n)) - local lhs = bit_or(m, n) - local rslt = bit_and(lhs, rhs) - return rslt -end - --------------------- --- bit lib interface - -bit = { - -- bit operations - bnot = bit_not, - band = bit_and, - bor = bit_or, - bxor = bit_xor, - brshift = bit_rshift, - blshift = bit_lshift, - bxor2 = bit_xor2, - blogic_rshift = bit_logic_rshift, - - -- utility func - tobits = to_bits, - tonumb = tbl_to_number, -} - -end - ---[[ -for i = 1, 100 do - for j = 1, 100 do - if(bit.bxor(i, j) ~= bit.bxor2(i, j)) then - error("bit.xor failed.") - end - end -end ---]] diff --git a/mods/default/furnace.lua b/mods/default/furnace.lua index 3206dbdf8..7496234f5 100644 --- a/mods/default/furnace.lua +++ b/mods/default/furnace.lua @@ -34,9 +34,9 @@ mod:block { local output_stack = data.inventory:get_stack(1, 0) local fuel_stack = data.inventory:get_stack(2, 0) - local ticks_remaining = bit.band(data.data, 0xfff) - local current_burn_time = bit.band(bit.brshift(data.data, 12), 0xfff) - local item_progress = bit.band(bit.brshift(data.data, 24), 0xff) + local ticks_remaining = data.meta:get_int("ticks_remaining") or 0 + local current_burn_time = data.meta:get_int("current_burn_time") or 0 + local item_progress = data.meta:get_int("item_progress") or 0 local recipe = openminer:registry():get_recipe(data.inventory) if recipe and recipe:type() ~= "smelt" then @@ -72,8 +72,8 @@ mod:block { data.inventory:set_stack(1, 0, recipe:result():item():name(), output_stack:amount() + recipe:result():amount()) end - local a = bit.blshift(bit.band(current_burn_time, 0xfff), 12) - local b = bit.blshift(bit.band(item_progress, 0xff), 24) - data.data = bit.band(ticks_remaining, 0xfff) + a + b + data.meta:set_int("ticks_remaining", ticks_remaining); + data.meta:set_int("current_burn_time", current_burn_time); + data.meta:set_int("item_progress", item_progress); end, } diff --git a/mods/default/init.lua b/mods/default/init.lua index 679cffee8..0fbcfb883 100644 --- a/mods/default/init.lua +++ b/mods/default/init.lua @@ -7,7 +7,6 @@ GUI_SCALE = 3 mod = LuaMod.new("default") -dofile("mods/default/bit.lua") -- FIXME dofile("mods/default/blocks.lua") dofile("mods/default/items.lua") dofile("mods/default/recipes.lua") diff --git a/server/source/lua/ScriptEngine.cpp b/server/source/lua/ScriptEngine.cpp index a6807a751..e540b8a47 100644 --- a/server/source/lua/ScriptEngine.cpp +++ b/server/source/lua/ScriptEngine.cpp @@ -11,6 +11,7 @@ * * ===================================================================================== */ +#include "BlockMetadata.hpp" #include "LuaCore.hpp" #include "LuaGUI.hpp" #include "LuaMod.hpp" @@ -66,7 +67,7 @@ void ScriptEngine::initUsertypes() { m_lua.new_usertype("BlockData", "inventory", &BlockData::inventory, - "data", &BlockData::data, + "meta", &BlockData::meta, "useAltTiles", &BlockData::useAltTiles ); @@ -106,6 +107,14 @@ void ScriptEngine::initUsertypes() { "z", &glm::ivec3::z ); + m_lua.new_usertype("BlockMetadata", + "get_string", &BlockMetadata::getLuaObject, + "set_string", &BlockMetadata::setString, + + "get_int", &BlockMetadata::getLuaObject, + "set_int", &BlockMetadata::setInt + ); + LuaCore::initUsertype(m_lua); LuaMod::initUsertype(m_lua); LuaGUI::initUsertype(m_lua); diff --git a/server/source/network/ServerCommandHandler.cpp b/server/source/network/ServerCommandHandler.cpp index eaef06d35..6732d75f3 100644 --- a/server/source/network/ServerCommandHandler.cpp +++ b/server/source/network/ServerCommandHandler.cpp @@ -131,7 +131,7 @@ void ServerCommandHandler::setupCallbacks() { BlockData *data = m_world.getBlockData(pos.x, pos.y, pos.z); if (data) { - packet >> data->data >> data->useAltTiles; + packet >> data->meta >> data->useAltTiles; } }); } diff --git a/server/source/world/ServerBlock.cpp b/server/source/world/ServerBlock.cpp index b1792b171..948e08f22 100644 --- a/server/source/world/ServerBlock.cpp +++ b/server/source/world/ServerBlock.cpp @@ -35,7 +35,7 @@ void ServerBlock::onTick(const glm::ivec3 &pos, std::unordered_mapdata << blockData->useAltTiles; + packet1 << blockData->meta << blockData->useAltTiles; server.sendToAllClients(packet1); if (blockData->inventory.hasChanged()) { diff --git a/server/source/world/ServerWorld.cpp b/server/source/world/ServerWorld.cpp index 1190ce7af..e50ed5e00 100644 --- a/server/source/world/ServerWorld.cpp +++ b/server/source/world/ServerWorld.cpp @@ -105,7 +105,7 @@ void ServerWorld::sendChunkData(const Client &client, ServerChunk *chunk) { sf::Packet packet1; packet1 << Network::Command::BlockDataUpdate << globalX << globalY << globalZ; - packet1 << blockData->data << blockData->useAltTiles; + packet1 << blockData->meta << blockData->useAltTiles; client.tcpSocket->send(packet1); sf::Packet packet2;