Merge pull request #616 from MihailRis/attached-tags

External content tags
This commit is contained in:
MihailRis 2025-09-19 22:49:17 +03:00 committed by GitHub
commit 8cdb6c03aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 181 additions and 29 deletions

View File

@ -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" = [
# ...
]
``

View File

@ -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" = [
# ...
]
```

View File

@ -306,3 +306,29 @@
### `имя_свойства@append`
Добавляет элементы в конец списка, вместо его полной перезаписи.
## Теги - *tags*
Теги позволяют обозначать обобщённые свойства блоков. Названия следует формировать как `префикс:имя_тега`.
Префикс не является обязательным, но позволяет избегать нежелательных логических коллизий. Пример:
```json
{
"tags": [
"core:ore",
"base_survival:food",
]
}
```
Теги блокам можно добавлять и из других паков, с помощью файла аш_пак:tags.toml`. Пример
```toml
"префикс:имя_тега" = [
"рандомный_пак:какой_то_блок",
"ещё_один_пак:предмет",
]
ругой_префиксругое_имя_тега" = [
# ...
]
```

View File

@ -65,3 +65,30 @@
- `number` - число
- `relation` - отношение текущего значения к изначальному (x/y)
- `vbar` - вертикальная шкала (используется по-умолчанию)
## Теги - *tags*
Теги позволяют обозначать обобщённые свойства предметов. Названия следует формировать как `префикс:имя_тега`.
Префикс не является обязательным, но позволяет избегать нежелательных логических коллизий. Пример:
```json
{
"tags": [
"core:fuel",
"base_survival:poison",
]
}
```
Теги предметам можно добавлять и из других паков, с помощью файла аш_пак:tags.toml`. Пример
```toml
"префикс:имя_тега" = [
"рандомный_пак:предмет",
"ещё_один_пак:какой_то_блок",
]
ругой_префиксругое_имя_тега" = [
# ...
]
```

View File

@ -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

View File

@ -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 <class T>

View File

@ -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<l_set_field>},
{"reload_script", lua::wrap<l_reload_script>},
{"has_tag", lua::wrap<l_has_tag>},
{"__get_tags", lua::wrap<l_get_tags>},
{"__pull_register_events", lua::wrap<l_pull_register_events>},
{NULL, NULL}
};

View File

@ -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<l_index>},
{"name", lua::wrap<l_name>},
@ -131,5 +146,6 @@ const luaL_Reg itemlib[] = {
{"uses", lua::wrap<l_uses>},
{"reload_script", lua::wrap<l_reload_script>},
{"has_tag", lua::wrap<l_has_tag>},
{"__get_tags", lua::wrap<l_get_tags>},
{NULL, NULL}
};