Модуль:GetField
Модуль предназначен для получения данных из кэшированных JSON-страниц и их использования в шаблонах. С его помощью можно получить поле по пути, найти id по значению или сразу собрать вызов шаблона по найденным данным.
Поля берутся из json страниц
Участник:IanComradeBot/component/название(пример: Участник:IanComradeBot/component/access.json)Участник:IanComradeBot/prototype/название(пример: Участник:IanComradeBot/prototype/tag.json)
Для подпроектов
Участник:IanComradeBot/component/Проект/название(пример: Участник:IanComradeBot/Goob/component/access.json)Участник:IanComradeBot/prototype/Проект/название(пример: Участник:IanComradeBot/Goob/prototype/tag.json)
Основные функции
get
Возвращает запись целиком или отдельное поле по её id.
Использование:
- {{#invoke:GetField
|get |id |pagePath |keyPath}}
Простые значения возвращаются как текст, а таблицы в JSON-виде.
Например, json сущности MopItem из Участник:IanComradeBot/component/meleeWeapon.json выглядит так:
"MopItem": {
"damage": {
"types": {
"Blunt": 10
}
},
...
},
то мы можем получить значение как как:
- {{#invoke:GetField
|get |MopItem |component/meleeWeapon.json |damage}} -> "types": {"Blunt": 10}} - {{#invoke:GetField
|get |MopItem |component/meleeWeapon.json |damage.types}} -> {"Blunt": 10} - {{#invoke:GetField
|get |MopItem |component/meleeWeapon.json |damage.types.Blunt}} -> 10
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Id записи. | Да |
|2 = | Путь до JSON-страницы, например component/meleeWeapon.json. | Да |
|3 = | Путь до поля внутри записи. Поддерживает вложенность через точку и индексы вида field.1 | Да |
getTpl
Строит вызов шаблона для одного id передавая в него развёрнутые поля записи.
Использование:
- {{#invoke:GetField
|getTpl |id |pagePath |template}}
Шаблон вызывается в виде {{Имя шаблона|id=...|...поля записи...}}. Вложенные таблицы передаются как плоские параметры, а также в JSON-виде там, где это нужно для сохранения структуры.
Пример:
- {{#invoke:GetField
|getTpl |MopItem |сomponent/spillable.json |сomponent/spillable}}
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Id записи. | Да |
|2 = | Путь до JSON-страницы. | Да |
|3 = | Имя шаблона, который будет вызван как {{Имя шаблона|id=...|...}}. | Да |
searchId / searchIdTpl
Обе функции ищут id по значению в указанном поле. Разница в результате:
searchIdвозвращает найденные id в виде JSON-массива.searchIdTplпо найденным id сразу вызывает шаблон.
Использование:
- {{#invoke:GetField
|searchId |searchValue |pagePath |keyPath}} - {{#invoke:GetField
|searchIdTpl |searchValue |pagePath |keyPath |template}} - {{#invoke:GetField
|searchIdTpl |pagePath |keyPath |template |searchType=path}}
Режимы поиска:
searchType=value— ищет id, у которых значение поля равно указанному значению. Это режим по умолчанию.searchType=key— ищет id, у которых в поле-таблице существует ключ с указанным именем.searchType=path— только дляsearchIdTpl; выводит все id, у которых поле по указанному пути существует и не пустое. В этом режиме первым параметром передаётсяpagePath, а не значение для поиска.
searchIdTpl вызывает шаблон в виде {{Имя шаблона|id=...|...поля записи...}}. Если найдено несколько id, вызовы собираются подряд через пробел.
Примеры:
- {{#invoke:GetField
|searchId |Elements |prototype/reaction.json |group}} -> Ошибка скрипта: Функции «searchId» не существует.
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Значение для поиска. | Да |
|2 = | Путь до JSON-страницы. | Да |
|3 = | Путь до поля внутри записи. Поддерживает вложенность через точку и индексы вида field.1 | Да |
|4 = | Имя шаблона, который будет вызван для каждого найденного id. | Только для searchIdTpl |
|searchType = | Режим поиска: value, key или path. | Нет; value |
hasComp
Проверяет, есть ли у сущности указанный компонент.
Использование:
- {{#invoke:GetField
|hasComp |entityId |componentName}}
Возвращает строку true или false.
Пример:
- {{#invoke:GetField
|hasComp |MopItem |Item}}
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Id сущности. | Да |
|2 = | Имя компонента для проверки. | Да |
searchStore / searchStoreTpl
Эти функции находят прототипы или компоненты содержащие указанный id, используя Участник:IanComradeBot/prototype_store.json или Участник:IanComradeBot/component_store.json.
Использование:
- {{#invoke:GetField
|searchStore |searchId |prototype |Название}} - {{#invoke:GetField
|searchStore |searchId |component |Название}} - {{#invoke:GetField
|searchStoreTpl |searchId |prototype |Название |Шаблон}}
searchStore возвращает JSON-массив id, найденных в компонентах/прототипах. searchStoreTpl по тем же id сразу вызывает шаблон, используя страницу вида prototype/Название.json или component/Название.json.
Примеры:
- {{#invoke:GetField
|searchStore |MopItem |component |itemBorgModule}} -> Ошибка скрипта: Функции «searchStore» не существует. - {{#invoke:GetField
|searchStore |MopItem |prototype |latheRecipe}} -> Ошибка скрипта: Функции «searchStore» не существует.
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Id, который ищется в хранилище. | Да |
|2 = | Тип: prototype или component. | Да |
|3 = | Имя хранилищя без .json. | Да |
|4 = | Имя шаблона, который будет вызван для каждого найденного id. | Только для searchStoreTpl |
getAll / getAllTpl
Эти функции получают все id прототипов или компонентов.
Использование:
getAll по умолчанию возвращает JSON-массив id.
getAllTpl вызывает шаблон для каждого id в виде {{Имя шаблона|id=...|...поля записи...}}.
Примеры:
- {{#invoke:GetField
|getAll |component/staticPrice.json}} -> выводит все id сущностей с этим компонентом в формате JSON - {{#invoke:GetField
|getAllTpl |component/staticPrice.json |component/staticPrice/wrapper}} -> выводит все id сущностей с этим компонентом обёрнутым в шаблон {{component/staticPrice/wrapper}}
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | Путь до JSON-страницы. | Да |
|2 = | Имя шаблона для getAllTpl. | Только для getAllTpl |
|replace = | Строка замены для getAll. Если задана, результат выводится построчно вместо JSON-массива. | Нет |
jsonList
Преобразует JSON в список, перечисление или простой текст. Подходит для быстрого вывода данных без отдельного шаблона.
Использование:
- {{#invoke:GetField
|jsonList |["a","b","c"]}} - {{#invoke:GetField
|jsonList |{"MopItem":"Швабра"}}} - {{#invoke:GetField
|jsonList |{"MopItem":"Швабра"} |type=enum}}
Основные параметры:
type— формат вывода:list,enumилиnone.prefix— префикс строки для режима списка. По умолчанию*.sep— разделитель между ключом и значением. По умолчанию:.replace— дополнительная обработка регулярным выражением уже собранной строки.key_replace,value_replace— обработка ключей и значений регулярным выражением по отдельности.
Примеры:
- {{#invoke:GetField
|jsonList |["a","b","c"]}} - {{#invoke:GetField
|jsonList |{"MopItem":"Швабра"} |type=list}} - {{#invoke:GetField
|jsonList |{"MopItem":"Швабра"} |type=none |key_replace=<nowiki>[[\1]]</nowiki>}}
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | JSON-строка. Можно также передать именованным параметром json. | Да |
|type = | Формат вывода: list, enum или none. | Нет; list |
|prefix = | Префикс строки для режима list. | Нет; * |
|sep = | Разделитель между ключом и значением. | Нет; : |
|key_replace = | Строка замены для ключей. | Нет; \1 |
|value_replace = | Строка замены для значений. | Нет; \1 |
|replace = | Строка замены для всего вывода. | Нет; \1 |
json
Преобразует JSON-объект или JSON-массив объектов в набор вызовов шаблона и сразу обрабатывает их.
Использование:
- {{#invoke:GetField
|json |{"MopItem":{"name":"Швабра"}} |Предмет}}
Если значение по id является объектом, его поля разворачиваются в параметры шаблона. Если значение простое, оно передаётся как value=....
Пример вызова, который будет собран функцией:
{{Предмет|id=MopItem|name=Швабра}}
| Параметр | Описание | Обязателен? |
|---|---|---|
|1 = | JSON-строка. | Да |
|2 = | Имя шаблона. | Да |
См. также
Примечания
- Если запись, поле или JSON-страница не найдены, функции обычно возвращают пустую строку.
- Функция
getвозвращает таблицы в JSON-виде. - В
searchIdиsearchIdTplзначения сравниваются как строки. - Параметр
keyPathподдерживает доступ к вложенным полям и индексам. getTplиsearchIdTplудобны, когда нужно не получить сырые данные, а сразу отрендерить карточку или другой шаблон.- Функции с
searchStoreработают только с генераторными страницами и хранилищами, где структура данных уже подготовлена под поиск по id. jsonиjsonListожидают корректный JSON; если строка не разбирается, результат будет пустым.
local p = {}
local cache = {}
local entryCache = {}
local function parse_indexed_part(part)
local key, idx = string.match(part, "^(.-)%[(%d+)%]$")
if key then
return key, tonumber(idx)
end
local num = tonumber(part)
if num then
return nil, num
end
return part, nil
end
local function get_by_path(tbl, path)
if not tbl or path == "" then return nil end
local cur = tbl
for part in string.gmatch(path, "([^%.]+)") do
local key, idx = parse_indexed_part(part)
if key and key ~= "" then
if type(cur) ~= "table" then return nil end
local nextCur = cur[key]
if nextCur == nil then
nextCur = cur["!type:" .. key]
end
cur = nextCur
end
if idx then
if type(cur) ~= "table" then return nil end
cur = cur[idx]
end
if cur == nil then return nil end
end
return cur
end
local function format_value(v)
if v == nil then return "" end
local t = type(v)
if t == "string" or t == "number" or t == "boolean" then
return tostring(v)
elseif t == "table" then
local max = 0
local hasNonNumber = false
for k in pairs(v) do
if type(k) ~= "number" then
hasNonNumber = true
break
else
if k > max then max = k end
end
end
if not hasNonNumber and max > 0 then
local out = {}
for i = 1, max do
out[#out + 1] = format_value(v[i])
end
return table.concat(out, ", ")
else
local out = {}
for k, val in pairs(v) do
out[#out + 1] = tostring(k) .. ": " .. format_value(val)
end
return table.concat(out, ", ")
end
else
return tostring(v)
end
end
local function to_nowiki(v)
local s = tostring(v)
local ok, res = pcall(mw.text.nowiki, s)
if ok and res then
return res
end
return mw.text.nowiki(s)
end
local function is_array(tbl)
local max = 0
local count = 0
for k in pairs(tbl) do
if type(k) ~= "number" then
return false
end
if k > max then max = k end
count = count + 1
end
return count > 0 and max == count
end
local function deep_copy(src)
local dst = {}
for k, v in pairs(src) do
if type(v) == "table" then
dst[k] = deep_copy(v)
else
dst[k] = v
end
end
return dst
end
local function deep_merge(dst, src)
for k, v in pairs(src) do
if type(v) == "table" and type(dst[k]) == "table" then
deep_merge(dst[k], v)
elseif type(v) == "table" then
dst[k] = deep_copy(v)
else
dst[k] = v
end
end
end
function p.findInProto(frame)
local args = frame.args or {}
local protoKey = args[1] or ""
local fieldId = args[2] or ""
if protoKey == "" or fieldId == "" then
return "[]"
end
local moduleName = "Module:IanComradeBot/prototype.json/data"
local data = cache[moduleName]
if not data then
local ok, loaded = pcall(mw.loadData, moduleName)
if not ok or not loaded then
return "[]"
end
data = loaded
cache[moduleName] = data
end
local proto = data[protoKey]
if type(proto) ~= "table" then
return "[]"
end
local value = proto[fieldId]
if value == nil then
return "[]"
end
local out = {}
local t = type(value)
if t == "table" then
for _, v in ipairs(value) do
out[#out + 1] = v
end
else
out[1] = value
end
return mw.text.jsonEncode(out)
end
function p.flattenField(frame)
local args = frame.args or {}
local id = args[1] or ""
local pagePath = args[2] or ""
if id == "" or pagePath == "" then return "" end
local baseUser = "IanComradeBot/"
local moduleName = "Module:" .. baseUser .. pagePath .. "/data"
local data = cache[moduleName]
if not data then
local ok, loaded = pcall(mw.loadData, moduleName)
if not ok or not loaded then return "" end
data = loaded
cache[moduleName] = data
end
local entry = data[id]
if entry == nil then
local idsTable = data.id
if type(idsTable) == "table" then
local specific = idsTable[id]
if type(specific) == "table" then
local base = data["default"]
if type(base) == "table" then
local merged = deep_copy(base)
deep_merge(merged, specific)
entry = merged
else
entry = deep_copy(specific)
end
end
end
end
if entry == nil then
local base = data["default"]
if type(base) == "table" then
entry = deep_copy(base)
else
entry = {}
end
end
if type(entry) ~= "table" then return "" end
local parts = {}
local function walk(tbl, prefix)
local keys = {}
for k in pairs(tbl) do keys[#keys + 1] = k end
table.sort(keys, function(a, b) return tostring(a) < tostring(b) end)
for _, k in ipairs(keys) do
local v = tbl[k]
local key = (prefix == "" and tostring(k) or prefix .. "." .. tostring(k))
if type(v) == "table" then
if is_array(v) then
local ok, json = pcall(mw.text.jsonEncode, v)
if ok and json then
parts[#parts + 1] = key .. "=" .. to_nowiki(json)
end
else
local ok, json = pcall(mw.text.jsonEncode, v)
if ok and json then
parts[#parts + 1] = key .. "=" .. to_nowiki(json)
end
walk(v, key)
end
else
parts[#parts + 1] = key .. "=" .. to_nowiki(v)
end
end
end
walk(entry, "")
return table.concat(parts, "|")
end
function p.get(frame)
local args = frame.args or {}
local id = args[1] or ""
local pagePath = args[2] or ""
local keyPath = args[3] or ""
if pagePath == "" then return "" end
local baseUser = "IanComradeBot/"
local moduleName = "Module:" .. baseUser .. pagePath .. "/data"
local data = cache[moduleName]
if not data then
local ok, loaded = pcall(mw.loadData, moduleName)
if not ok or not loaded then return "" end
data = loaded
cache[moduleName] = data
end
local entryKey = moduleName .. "|" .. (id ~= "" and id or "default")
local entry = entryCache[entryKey]
if not entry then
if id ~= "" then entry = data[id] end
if entry == nil then entry = data["default"] end
entryCache[entryKey] = entry
end
if entry == nil then return "" end
if keyPath == "" then
return format_value(entry)
end
local value = get_by_path(entry, keyPath)
return format_value(value)
end
function p.getTpl(frame)
local args = frame.args or {}
local id = args[1] or ""
local pagePath = args[2] or ""
local tplPath = args[3] or ""
if id == "" or pagePath == "" or tplPath == "" then
return ""
end
local extra = p.flattenField({ args = { id, pagePath } }) or ""
local tplStr = "{{" .. tostring(tplPath) .. "|id=" .. tostring(id)
if extra ~= "" then
tplStr = tplStr .. "|" .. extra
end
tplStr = tplStr .. "}}"
return tplStr
end
function p.getTplProto(frame)
local args = frame.args or {}
local searchId = args[1] or ""
local protoId = args[2] or ""
local tplPath = args[3] or ""
local pagePath = "prototype/" .. protoId .. ".json"
if searchId == "" or protoId == "" or tplPath == "" then
return ""
end
local idsJson = p.findInProto({ args = { searchId, protoId } })
local ok, ids = pcall(mw.text.jsonDecode, idsJson or "")
if not ok or type(ids) ~= "table" or #ids == 0 then
return ""
end
local out = {}
for _, id in ipairs(ids) do
local tpl = p.getTpl({ args = { id, pagePath, tplPath } })
if tpl ~= "" then
out[#out + 1] = tpl
end
end
return table.concat(out, "\n")
end
return p