From 43a7331f62dee5c16f88031c592d687ea5fa7f74 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 19 Sep 2025 22:16:28 +0300 Subject: [PATCH 1/2] add 'tags.toml' file --- res/scripts/post_content.lua | 28 +++++++-------- src/content/ContentLoader.cpp | 19 ++++++++++ src/logic/scripting/lua/libs/libblock.cpp | 42 ++++++++++++++++------- src/logic/scripting/lua/libs/libitem.cpp | 16 +++++++++ 4 files changed, 76 insertions(+), 29 deletions(-) diff --git a/res/scripts/post_content.lua b/res/scripts/post_content.lua index 1b69f42f..b512882d 100644 --- a/res/scripts/post_content.lua +++ b/res/scripts/post_content.lua @@ -14,28 +14,20 @@ for name, _ in pairs(user_props) do end -- remove undefined properties and build tags set -local function process_properties(properties) - for id, props in pairs(properties) do - local tags_set = nil - for propname, value in pairs(props) do - if propname == "tags" then - if #value > 0 then - tags_set = tags_set or {} - end - for _, tag in ipairs(value) do - tags_set[tag] = true - end - end +local function process_properties(lib) + for id, props in pairs(lib.properties) do + for propname, _ in pairs(props) do if not table.has(names, propname) then props[propname] = nil end end - props.tags_set = tags_set + + props.tags_set = lib.__get_tags(id) end end -process_properties(block.properties) -process_properties(item.properties) +process_properties(block) +process_properties(item) local function make_read_only(t) setmetatable(t, { @@ -68,7 +60,11 @@ local function cache_names(library) end function library.has_tag(id, tag) - local tags_set = library.properties[id].tags_set + if id == nil then + error("id is nil") + end + local props = library.properties[id] + local tags_set = props.tags_set if tags_set then return tags_set[tag] else diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 1527d98b..ea29e27c 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -413,6 +413,25 @@ void ContentLoader::load() { if (io::exists(contentFile)) { loadContent(io::read_json(contentFile)); } + + // Load attached tags + io::path tagsFile = folder / "tags.toml"; + if (io::exists(tagsFile)) { + auto tagsMap = io::read_object(tagsFile); + for (const auto& [key, list] : tagsMap.asObject()) { + for (const auto& id : list) { + const auto& stringId = id.asString(); + if (auto block = builder.blocks.get(stringId)) { + block->tags.push_back(key); + if (auto item = builder.items.get(stringId + BLOCK_ITEM_SUFFIX)) { + item->tags.push_back(key); + } + } else if (auto item = builder.items.get(stringId)) { + item->tags.push_back(key); + } + } + } + } } template diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index 29f7747c..e72bf96f 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -20,21 +20,21 @@ using namespace scripting; -static inline const Block* require_block(lua::State* L) { +static inline const Block* get_block_def(lua::State* L) { auto indices = content->getIndices(); auto id = lua::tointeger(L, 1); return indices->blocks.get(id); } static inline int l_get_def(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushstring(L, def->name); } return 0; } static int l_material(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushstring(L, def->material); } return 0; @@ -59,14 +59,14 @@ static int l_index(lua::State* L) { } static int l_is_extended(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushboolean(L, def->rt.extended); } return 0; } static int l_get_size(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushivec_stack(L, glm::ivec3(def->size)); } return 0; @@ -343,14 +343,14 @@ static int l_is_replaceable_at(lua::State* L) { } static int l_caption(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushstring(L, def->caption); } return 0; } static int l_get_textures(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { lua::createtable(L, 6, 0); for (size_t i = 0; i < 6; i++) { lua::pushstring(L, def->defaults.textureFaces[i]); // TODO: variant argument @@ -363,7 +363,7 @@ static int l_get_textures(lua::State* L) { static int l_model_name(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { // TODO: variant argument const auto& modelName = def->defaults.model.name; if (modelName.empty()) { @@ -375,7 +375,7 @@ static int l_model_name(lua::State* L) { } static int l_get_model(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { // TODO: variant argument return lua::pushlstring(L, BlockModelTypeMeta.getName(def->defaults.model.type)); } @@ -383,7 +383,7 @@ static int l_get_model(lua::State* L) { } static int l_get_hitbox(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { size_t rotation = lua::tointeger(L, 2); if (def->rotatable) { rotation %= def->rotations.MAX_COUNT; @@ -404,14 +404,14 @@ static int l_get_hitbox(lua::State* L) { } static int l_get_rotation_profile(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushstring(L, def->rotations.name); } return 0; } static int l_get_picking_item(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { return lua::pushinteger(L, def->rt.pickingItem); } return 0; @@ -699,7 +699,7 @@ static int l_reload_script(lua::State* L) { } static int l_has_tag(lua::State* L) { - if (auto def = require_block(L)) { + if (auto def = get_block_def(L)) { auto tag = lua::require_string(L, 2); const auto& tags = def->rt.tags; return lua::pushboolean(L, tags.find(content->getTagIndex(tag)) != tags.end()); @@ -707,6 +707,21 @@ static int l_has_tag(lua::State* L) { return 0; } +static int l_get_tags(lua::State* L) { + if (auto def = get_block_def(L)) { + if (def->tags.empty()) { + return 0; + } + lua::createtable(L, 0, def->tags.size()); + for (const auto& tag : def->tags) { + lua::pushboolean(L, true); + lua::setfield(L, tag); + } + return 1; + } + return 0; +} + static int l_pull_register_events(lua::State* L) { auto events = blocks_agent::pull_register_events(); if (events.empty()) @@ -766,6 +781,7 @@ const luaL_Reg blocklib[] = { {"set_field", lua::wrap}, {"reload_script", lua::wrap}, {"has_tag", lua::wrap}, + {"__get_tags", lua::wrap}, {"__pull_register_events", lua::wrap}, {NULL, NULL} }; diff --git a/src/logic/scripting/lua/libs/libitem.cpp b/src/logic/scripting/lua/libs/libitem.cpp index b26e524c..79c03c2a 100644 --- a/src/logic/scripting/lua/libs/libitem.cpp +++ b/src/logic/scripting/lua/libs/libitem.cpp @@ -117,6 +117,21 @@ static int l_has_tag(lua::State* L) { return 0; } +static int l_get_tags(lua::State* L) { + if (auto def = get_item_def(L, 1)) { + if (def->tags.empty()) { + return 0; + } + lua::createtable(L, 0, def->tags.size()); + for (const auto& tag : def->tags) { + lua::pushboolean(L, true); + lua::setfield(L, tag); + } + return 1; + } + return 0; +} + const luaL_Reg itemlib[] = { {"index", lua::wrap}, {"name", lua::wrap}, @@ -131,5 +146,6 @@ const luaL_Reg itemlib[] = { {"uses", lua::wrap}, {"reload_script", lua::wrap}, {"has_tag", lua::wrap}, + {"__get_tags", lua::wrap}, {NULL, NULL} }; From 77947a4822338f4c60b2a9fc2f108a1fada79eef Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 19 Sep 2025 22:31:24 +0300 Subject: [PATCH 2/2] update doc/*/block-properties.md, doc/*/item-properties.md --- doc/en/block-properties.md | 26 ++++++++++++++++++++++++++ doc/en/item-properties.md | 26 ++++++++++++++++++++++++++ doc/ru/block-properties.md | 26 ++++++++++++++++++++++++++ doc/ru/item-properties.md | 27 +++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index 60f87722..1244da99 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -297,3 +297,29 @@ Methods are used to manage the overwriting of properties when extending a block ### `property_name@append` Adds elements to the end of the list instead of completely overwriting it. + +## Tags + +Tags allow you to designate general properties of blocks. Names should be formatted as `prefix:tag_name`. +The prefix is ​​optional, but helps avoid unwanted logical collisions. Example: + +```json +{ + "tags": [ + "core:ore", + "base_survival:food", + ] +} +``` + +Block tags can also be added from other packs using the `your_pack:tags.toml` file. Example: + +```toml +"prefix:tag_name" = [ + "random_pack:some_block", + "another_pack:item", +] +"other_prefix:other_tag_name" = [ + # ... +] +`` diff --git a/doc/en/item-properties.md b/doc/en/item-properties.md index 8abcb93c..7bef0766 100644 --- a/doc/en/item-properties.md +++ b/doc/en/item-properties.md @@ -66,3 +66,29 @@ Property status is displayed in the inventory interface. Display method is defin - `number` - number - `relation` - current value to initial value (x/y) - `vbar` - vertical scale (used by default) + +## Tags + +Tags allow you to designate general properties of items. Names should be formatted as `prefix:tag_name`. +The prefix is ​​optional, but helps avoid unwanted logical collisions. Example: + +```json +{ + "tags": [ + "core:fuel", + "base_survival:poison", + ] +} +``` + +Tags can also be added to items from other packs using the `your_pack:tags.toml` file. Example + +```toml +"prefix:tag_name" = [ + "random_pack:item", + "another_pack:some_block", +] +"other_prefix:other_tag_name" = [ + # ... +] +``` diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index 601a0dba..0003cb92 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -306,3 +306,29 @@ ### `имя_свойства@append` Добавляет элементы в конец списка, вместо его полной перезаписи. + +## Теги - *tags* + +Теги позволяют обозначать обобщённые свойства блоков. Названия следует формировать как `префикс:имя_тега`. +Префикс не является обязательным, но позволяет избегать нежелательных логических коллизий. Пример: + +```json +{ + "tags": [ + "core:ore", + "base_survival:food", + ] +} +``` + +Теги блокам можно добавлять и из других паков, с помощью файла `ваш_пак:tags.toml`. Пример + +```toml +"префикс:имя_тега" = [ + "рандомный_пак:какой_то_блок", + "ещё_один_пак:предмет", +] +"другой_префикс:другое_имя_тега" = [ + # ... +] +``` diff --git a/doc/ru/item-properties.md b/doc/ru/item-properties.md index 8a75ca72..cb45827a 100644 --- a/doc/ru/item-properties.md +++ b/doc/ru/item-properties.md @@ -65,3 +65,30 @@ - `number` - число - `relation` - отношение текущего значения к изначальному (x/y) - `vbar` - вертикальная шкала (используется по-умолчанию) + + +## Теги - *tags* + +Теги позволяют обозначать обобщённые свойства предметов. Названия следует формировать как `префикс:имя_тега`. +Префикс не является обязательным, но позволяет избегать нежелательных логических коллизий. Пример: + +```json +{ + "tags": [ + "core:fuel", + "base_survival:poison", + ] +} +``` + +Теги предметам можно добавлять и из других паков, с помощью файла `ваш_пак:tags.toml`. Пример + +```toml +"префикс:имя_тега" = [ + "рандомный_пак:предмет", + "ещё_один_пак:какой_то_блок", +] +"другой_префикс:другое_имя_тега" = [ + # ... +] +```