diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 7adb8d3b..5fe39b1b 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -24,6 +24,7 @@ #include "data/StructLayout.hpp" namespace fs = std::filesystem; +using namespace data; static debug::Logger logger("content-loader"); @@ -117,6 +118,30 @@ void ContentLoader::fixPackIndices() { } } +static void perform_user_block_fields( + const std::string& blockName, StructLayout& layout +) { + if (layout.size() > MAX_USER_BLOCK_FIELDS_SIZE) { + throw std::runtime_error( + util::quote(blockName) + + " fields total size exceeds limit (" + + std::to_string(layout.size()) + "/" + + std::to_string(MAX_USER_BLOCK_FIELDS_SIZE) + ")"); + } + for (const auto& field : layout) { + if (field.name.at(0) == '.') { + throw std::runtime_error( + util::quote(blockName) + " field " + field.name + + ": user field may not start with '.'"); + } + } + + std::vector fields; + fields.insert(fields.end(), layout.begin(), layout.end()); + // add built-in fields here + layout = StructLayout::create(fields); +} + void ContentLoader::loadBlock( Block& def, const std::string& name, const fs::path& file ) { @@ -253,15 +278,10 @@ void ContentLoader::loadBlock( root.at("tick-interval").get(def.tickInterval); if (root.has("fields")) { - def.dataStruct = std::make_unique(); + def.dataStruct = std::make_unique(); def.dataStruct->deserialize(root["fields"]); - if (def.dataStruct->size() > MAX_BLOCK_FIELDS_SIZE) { - throw std::runtime_error( - util::quote(def.name) + - " fields total size exceeds limit (" + - std::to_string(def.dataStruct->size()) + "/" + - std::to_string(MAX_BLOCK_FIELDS_SIZE) + ")"); - } + + perform_user_block_fields(def.name, *def.dataStruct); } if (def.tickInterval == 0) { diff --git a/src/data/StructLayout.cpp b/src/data/StructLayout.cpp index a7af3e91..a3e0fd23 100644 --- a/src/data/StructLayout.cpp +++ b/src/data/StructLayout.cpp @@ -385,7 +385,7 @@ void StructLayout::deserialize(const dv::value& src) { fieldmap["convert-strategy"].asString() ); } - fields.push_back(Field {type, name, elements, convertStrategy}); + fields.push_back(Field (type, name, elements, convertStrategy)); } *this = create(fields); } diff --git a/src/data/StructLayout.hpp b/src/data/StructLayout.hpp index 2c3ee65e..02a5a435 100644 --- a/src/data/StructLayout.hpp +++ b/src/data/StructLayout.hpp @@ -81,6 +81,18 @@ namespace data { /// @brief Byte size of the field int size; + Field( + FieldType type, + std::string name, + int elements, + FieldConvertStrategy strategy=FieldConvertStrategy::RESET + ) : type(type), + name(std::move(name)), + elements(elements), + convertStrategy(strategy), + offset(0), + size(0) {} + bool operator==(const Field& o) const { return type == o.type && name == o.name && @@ -233,6 +245,14 @@ namespace data { return totalSize; } + [[nodiscard]] const auto begin() const { + return fields.begin(); + } + + [[nodiscard]] const auto end() const { + return fields.end(); + } + /// @brief Convert structure data from srcLayout to this layout. /// @param srcLayout source structure layout /// @param src source data diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index f06f052d..d09cbd99 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -1,5 +1,6 @@ #include "Block.hpp" +#include #include #include "core_defs.hpp" @@ -141,3 +142,10 @@ void Block::cloneTo(Block& dst) { dst.inventorySize = inventorySize; dst.tickInterval = tickInterval; } + +static std::set> RESERVED_BLOCK_FIELDS { +}; + +bool Block::isReservedBlockField(std::string_view view) { + return RESERVED_BLOCK_FIELDS.find(view) != RESERVED_BLOCK_FIELDS.end(); +} diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 555d0f05..3ba6785a 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -26,7 +26,7 @@ inline constexpr uint FACE_PZ = 5; /// complex hitboxes inline constexpr uint BLOCK_AABB_GRID = 16; -inline constexpr size_t MAX_BLOCK_FIELDS_SIZE = 240; +inline constexpr size_t MAX_USER_BLOCK_FIELDS_SIZE = 240; inline std::string DEFAULT_MATERIAL = "base:stone"; @@ -222,6 +222,8 @@ public: ~Block(); void cloneTo(Block& dst); + + static bool isReservedBlockField(std::string_view view); }; inline glm::ivec3 get_ground_direction(const Block& def, int rotation) { diff --git a/test/data/StructLayout.cpp b/test/data/StructLayout.cpp index 4933111a..37baec35 100644 --- a/test/data/StructLayout.cpp +++ b/test/data/StructLayout.cpp @@ -117,9 +117,9 @@ TEST(StructLayout, ConvertWithLoss) { TEST(StructLayout, Serialization) { std::vector fields { - Field {FieldType::CHAR, "text", 5}, - Field {FieldType::I16, "someint", 1}, - Field {FieldType::F64, "pi", 1}, + Field (FieldType::CHAR, "text", 5), + Field (FieldType::I16, "someint", 1), + Field (FieldType::F64, "pi", 1), }; auto layout1 = StructLayout::create(fields); auto serialized = layout1.serialize();