diff --git a/docs/lua-api-cpp.md b/docs/lua-api-cpp.md index d42990db..229bb4b1 100644 --- a/docs/lua-api-cpp.md +++ b/docs/lua-api-cpp.md @@ -11,6 +11,7 @@ - `string mod_name()` - `bool is_opaque()` - `ItemStack get_item_drop()` +- `BlockParam param()` ## BlockData diff --git a/source/client/world/ChunkBuilder.cpp b/source/client/world/ChunkBuilder.cpp index 319c1e83..2c152961 100644 --- a/source/client/world/ChunkBuilder.cpp +++ b/source/client/world/ChunkBuilder.cpp @@ -49,7 +49,8 @@ std::array ChunkBuilder::buildChunk(const Cli const gk::FloatBox &boundingBox = block.boundingBox(); - u8f orientation = block.isRotatable() ? chunk.getData(x, y, z) & 0x1F : 0; + u8f orientation = block.isRotatable() + ? block.param().getParam(BlockParam::Rotation, chunk.getData(x, y, z)) : 0; const glm::mat3 &orientMatrix = orientMatrices[orientation]; if (block.drawType() == BlockDrawType::Solid diff --git a/source/common/world/Block.cpp b/source/common/world/Block.cpp index 42111fc9..872b867e 100644 --- a/source/common/world/Block.cpp +++ b/source/common/world/Block.cpp @@ -45,7 +45,7 @@ void Block::serialize(sf::Packet &packet) const { << m_hardness << m_harvestRequirements << m_itemDrop << m_itemDropAmount << m_tiles << m_boundingBox << m_isOpaque << m_isLightSource << m_canUpdate << m_canBeActivated << m_colorMultiplier << m_isRotatable << m_inventoryImage << m_groups - << m_fogDepth << m_fogColor; + << m_fogDepth << m_fogColor << m_param; } void Block::deserialize(sf::Packet &packet) { @@ -56,7 +56,7 @@ void Block::deserialize(sf::Packet &packet) { >> m_hardness >> m_harvestRequirements >> m_itemDrop >> m_itemDropAmount >> m_tiles >> m_boundingBox >> m_isOpaque >> m_isLightSource >> m_canUpdate >> m_canBeActivated >> m_colorMultiplier >> m_isRotatable >> m_inventoryImage >> m_groups - >> m_fogDepth >> m_fogColor; + >> m_fogDepth >> m_fogColor >> m_param; m_id = id; m_drawType = BlockDrawType(drawType); @@ -71,7 +71,8 @@ void Block::initUsertype(sol::state &lua) { "label", &Block::label, "mod_name", &Block::modName, "is_opaque", &Block::isOpaque, - "get_item_drop", &Block::getItemDrop + "get_item_drop", &Block::getItemDrop, + "param", (const BlockParam &(Block::*)() const)&Block::param ); } diff --git a/source/common/world/Block.hpp b/source/common/world/Block.hpp index 38c803ea..987c9548 100644 --- a/source/common/world/Block.hpp +++ b/source/common/world/Block.hpp @@ -36,6 +36,7 @@ #include #include +#include "BlockParam.hpp" #include "ItemStack.hpp" #include "TilesDef.hpp" @@ -126,6 +127,9 @@ class Block : public gk::ISerializable { const gk::Color &fogColor() const { return m_fogColor; } void setFogColor(const gk::Color &fogColor) { m_fogColor = fogColor; } + const BlockParam ¶m() const { return m_param; } + BlockParam ¶m() { return m_param; } + static void initUsertype(sol::state &lua); protected: @@ -165,6 +169,8 @@ class Block : public gk::ISerializable { float m_fogDepth = 0; gk::Color m_fogColor = gk::Color::White; + + BlockParam m_param{*this}; }; #endif // BLOCK_HPP_ diff --git a/source/common/world/BlockParam.cpp b/source/common/world/BlockParam.cpp new file mode 100644 index 00000000..02b07bed --- /dev/null +++ b/source/common/world/BlockParam.cpp @@ -0,0 +1,100 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * 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 + * + * ===================================================================================== + */ +#include + +#include + +#include "Block.hpp" +#include "BlockParam.hpp" + +void BlockParam::serialize(sf::Packet &packet) const { + packet << m_totalSize << m_allocatedBits; +} + +void BlockParam::deserialize(sf::Packet &packet) { + packet >> m_totalSize >> m_allocatedBits; +} + +void BlockParam::allocateBits(u8 type, u8 size) { + auto it = m_allocatedBits.find(type); + if (it != m_allocatedBits.end()) { + gkWarning() << "Can't allocate param type" << getTypeName(type) << "twice in block" << m_block.stringID(); + } + else if (m_totalSize + size <= 16) { + m_allocatedBits.emplace(type, Param{m_totalSize, size}); + + m_totalSize += size; + + // gkDebug() << "Allocated" << (int)size << "bits for type" << getTypeName(type) << "in block" << m_block.stringID(); + } + else { + gkError() << "Failed to allocate bits for param" << getTypeName(type) << "in block" << m_block.stringID(); + gkError() << "Reason: Can't allocate more than 16 bits. Allocated bits:"; + for (auto &it : m_allocatedBits) { + gkError() << "\t-" << getTypeName(it.first) << "=" << (int)it.second.size; + } + } +} + +u16 BlockParam::getParam(u8 type, u16 data) const { + auto it = m_allocatedBits.find(type); + if (it == m_allocatedBits.end()) { + gkWarning() << "Failed to get param" << getTypeName(type) << "in block" << m_block.stringID(); + return 0; + } + + return (data >> it->second.offset) & ~(~0u << it->second.size); +} + +u16 BlockParam::setParam(u8 type, u16 data, u16 param) { + auto it = m_allocatedBits.find(type); + if (it == m_allocatedBits.end()) { + gkWarning() << "Failed to set param" << getTypeName(type) << "in block" << m_block.stringID(); + return 0; + } + + u16 mask = ~(~0u << it->second.size) << it->second.offset; + param <<= it->second.offset; + if ((param & ~mask) != 0) + gkWarning() << "Block param overflow for type" << getTypeName(type) << "in block" << m_block.stringID(); + + return (data & ~mask) | (param & mask); +} + +std::string BlockParam::getTypeName(u8 type) { + std::array names = { + "Rotation", + }; + + return names[type]; +} + +// Please update 'docs/lua-api-cpp.md' if you change this +void BlockParam::initUsertype(sol::state &lua) { + lua.new_usertype("BlockParam"); +} + diff --git a/source/common/world/BlockParam.hpp b/source/common/world/BlockParam.hpp new file mode 100644 index 00000000..322cfee1 --- /dev/null +++ b/source/common/world/BlockParam.hpp @@ -0,0 +1,82 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * 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 + * + * ===================================================================================== + */ +#ifndef BLOCKPARAM_HPP_ +#define BLOCKPARAM_HPP_ + +#include +#include + +#include +#include + +#include "NetworkUtils.hpp" + +namespace sol { class state; } + +class Block; + +class BlockParam : public gk::ISerializable { + public: + BlockParam(Block &block) : m_block(block) {} + + void serialize(sf::Packet &packet) const override; + void deserialize(sf::Packet &packet) override; + + enum Type { + Rotation, + + Count + }; + + void allocateBits(u8 type, u8 size); + + u16 getParam(u8 type, u16 data) const; + u16 setParam(u8 type, u16 data, u16 param); + + static std::string getTypeName(u8 type); + + static void initUsertype(sol::state &lua); + + private: + Block &m_block; + u8 m_totalSize = 0; + + struct Param : public gk::ISerializable { + Param() = default; + Param(u8 _offset, u8 _size) : offset(_offset), size(_size) {} + + void serialize(sf::Packet &packet) const override { packet << offset << size; } + void deserialize(sf::Packet &packet) override { packet >> offset >> size; } + + u8 offset; + u8 size; + }; + + std::unordered_map m_allocatedBits; +}; + +#endif // BLOCKPARAM_HPP_ diff --git a/source/server/lua/loader/LuaBlockLoader.cpp b/source/server/lua/loader/LuaBlockLoader.cpp index 851500a9..76b4859f 100644 --- a/source/server/lua/loader/LuaBlockLoader.cpp +++ b/source/server/lua/loader/LuaBlockLoader.cpp @@ -57,6 +57,8 @@ void LuaBlockLoader::loadBlock(const sol::table &table) const { item->setIsBlock(true); loadGroups(block, *item, table); + + loadParams(block); } inline void LuaBlockLoader::loadProperties(ServerBlock &block, const sol::table &table) const { @@ -164,3 +166,8 @@ inline void LuaBlockLoader::loadGroups(ServerBlock &block, Item &item, const sol } } +void LuaBlockLoader::loadParams(ServerBlock &block) const { + if (block.isRotatable()) + block.param().allocateBits(BlockParam::Type::Rotation, 5); +} + diff --git a/source/server/lua/loader/LuaBlockLoader.hpp b/source/server/lua/loader/LuaBlockLoader.hpp index 4e3ff4a7..eb0392d5 100644 --- a/source/server/lua/loader/LuaBlockLoader.hpp +++ b/source/server/lua/loader/LuaBlockLoader.hpp @@ -45,8 +45,8 @@ class LuaBlockLoader { void loadDrawType(ServerBlock &block, const sol::table &table) const; void loadItemDrop(ServerBlock &block, const sol::table &table) const; void loadColorMultiplier(ServerBlock &block, const sol::table &table) const; - void loadGroups(ServerBlock &block, Item &item, const sol::table &table) const; + void loadParams(ServerBlock &block) const; LuaMod &m_mod; };