Модуль:Entity Sprite/all: различия между версиями

мНет описания правки
Нет описания правки
 
(не показаны 63 промежуточные версии этого же участника)
Строка 1: Строка 1:
local p = {}
local p = {}
local JsonPaths = require('Module:JsonPaths')


local function deepEqual(t1, t2)
local function normalizeSpritePath(path)
    if t1 == t2 then return true end
if path == nil then
    if type(t1) ~= "table" or type(t2) ~= "table" then return false end
return nil
end


    local function isArray(t)
path = mw.text.trim(tostring(path))
        local count = 0
path = path:gsub("^/Textures/?", "")
        for k in pairs(t) do
            if type(k) ~= "number" then return false end
            count = count + 1
        end
        return count == #t
    end


    if isArray(t1) and isArray(t2) then
return path
        if #t1 ~= #t2 then return false end
end
        for i = 1, #t1 do
            if not deepEqual(t1[i], t2[i]) then
                return false
            end
        end
        return true
    end


    for k, v in pairs(t1) do
local function normalizeData(data)
        if t2[k] == nil or not deepEqual(v, t2[k]) then
if type(data) ~= "table" then
            return false
return nil
        end
end
    end


    for k, v in pairs(t2) do
if type(data.id) == "table" then
        if t1[k] == nil or not deepEqual(v, t1[k]) then
return data.id
            return false
end
        end
    end


    return true
return data
end
end


local function getInsensitiveKey(t, target)
local function buildEntryKey(entry)
    target = target:lower()
local parts = {}
    for k, v in pairs(t) do
 
        if type(k) == "string" and k:lower() == target then
local function addField(name, value)
            return v
if value ~= nil then
        end
table.insert(parts, name .. "=" .. tostring(value))
    end
end
    return nil
end
 
addField("sprite", normalizeSpritePath(entry.sprite))
addField("state", entry.state)
addField("scale", entry.scale)
addField("enableOverrideDir", entry.enableOverrideDir)
addField("overrideDir", entry.overrideDir)
 
if entry.layers and type(entry.layers) == "table" then
local layers = {}
 
for _, layer in ipairs(entry.layers) do
local layerParts = {}
 
for k, v in pairs(layer) do
if type(v) ~= "table" then
layerParts[#layerParts + 1] = k .. "=" .. tostring(v)
end
end
 
table.sort(layerParts)
table.insert(layers, table.concat(layerParts, ","))
end
 
table.sort(layers)
table.insert(parts, "layers=" .. table.concat(layers, "|"))
end
 
table.sort(parts)
return table.concat(parts, ";")
end
 
local function getSpriteStates(entry)
local result = {}
 
if entry.layers and type(entry.layers) == "table" then
for _, layer in ipairs(entry.layers) do
if layer.visible ~= false and layer.state then
table.insert(result, {
state = tostring(layer.state),
sprite = normalizeSpritePath(layer.sprite or entry.sprite)
})
end
end
elseif entry.state and entry.sprite then
table.insert(result, {
state = tostring(entry.state),
sprite = normalizeSpritePath(entry.sprite)
})
end
 
return (#result > 0) and result or nil
end
end


local function getSpritePath(entry)
local function getSpritePath(entry)
    local spriteField = getInsensitiveKey(entry, "Sprite")
if entry.sprite then
    local iconField = getInsensitiveKey(entry, "Icon")
return normalizeSpritePath(entry.sprite)
end
 
if entry.layers and type(entry.layers) == "table" then
for _, layer in ipairs(entry.layers) do
if layer.sprite then
return normalizeSpritePath(layer.sprite)
end
end
end
 
return nil
end
 
local function splitCsv(value)
local result = {}
 
if value == nil then
return nil
end
 
value = mw.text.trim(tostring(value))
if value == "" then
return nil
end
 
for part in mw.text.gsplit(value, ",", true) do
local item = mw.text.trim(part)
if item ~= "" then
table.insert(result, item)
end
end
 
return (#result > 0) and result or nil
end
 
local function buildSet(value)
local list = splitCsv(value)
if not list then
return nil
end
 
local set = {}
for _, item in ipairs(list) do
set[item] = true
end
 
return set
end
 
local function getParents(parentData, id)
if not parentData or type(parentData) ~= "table" or not id then
return nil
end
 
local parents = parentData[id]
if type(parents) ~= "table" then
return nil
end
 
return parents
end
 
local function hasAnyParent(parents, set)
if not parents or not set then
return false
end
 
for _, parent in ipairs(parents) do
if set[parent] then
return true
end
end
 
return false
end


    if spriteField and spriteField.sprite then
local function shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData)
        return spriteField.sprite
local parents = getParents(parentData, id)
    elseif iconField and iconField.sprite then
 
        return iconField.sprite
if whitelistSet and not hasAnyParent(parents, whitelistSet) then
    elseif spriteField and spriteField.layers then
return false
        for _, layer in pairs(spriteField.layers) do
end
            if layer.sprite then
 
                return layer.sprite
if blacklistSet and hasAnyParent(parents, blacklistSet) then
            end
return false
        end
end
    end
 
    return nil
return true
end
end


local function getSpriteState(entry)
local function filterSpriteData(spriteData, parentData, whitelistSet, blacklistSet, project)
    local spriteBlock = getInsensitiveKey(entry, "Sprite")
local result = {}
    if spriteBlock then
        if spriteBlock.state then
            return spriteBlock.state
        elseif spriteBlock.layers then
            for _, layer in pairs(spriteBlock.layers) do
                if layer.state then
                    return layer.state
                end
            end
        end
    end


    local iconBlock = getInsensitiveKey(entry, "Icon")
for id, entry in pairs(spriteData) do
    if iconBlock and iconBlock.state then
if shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData) then
        return iconBlock.state
if project == "" or JsonPaths.has(id, project) then
    end
result[id] = entry
end
end
end


    return nil
return result
end
end


local function generateRepeatTemplate(data)
local function buildFileLink(id, project)
    local spriteGroups = {}
return "[[:Файл:" .. JsonPaths.prefixFile(id) .. ".png]]"
end


    for _, entry in pairs(data) do
local function buildSpriteUrl(baseUrl, spritePath)
        local found = false
return baseUrl .. spritePath
        for _, group in pairs(spriteGroups) do
end
            if deepEqual(getInsensitiveKey(entry, "Sprite"), getInsensitiveKey(group[1], "Sprite")) and
 
              deepEqual(entry.EntityStorageVisuals, group[1].EntityStorageVisuals) and
local function buildSpritePathLink(baseUrl, spritePath)
              deepEqual(getInsensitiveKey(entry, "Icon"), getInsensitiveKey(group[1], "Icon")) then
local url = buildSpriteUrl(baseUrl, spritePath)
                table.insert(group, entry)
return "[" .. url .. " " .. spritePath .. "]"
                found = true
end
                break
            end
        end


        if not found then
local function buildStateLink(baseUrl, spritePath, state)
            table.insert(spriteGroups, {entry})
local url = buildSpriteUrl(baseUrl, spritePath) .. "/" .. state .. ".png"
        end
return "[" .. url .. " " .. state .. "]"
    end
end


    local result = {}
local function buildSpriteStateLinks(baseUrl, states)
    for _, group in pairs(spriteGroups) do
if not states or #states == 0 then
        if #group > 1 then
return ""
            local idLinks = {}
end
            for _, entry in pairs(group) do
                table.insert(idLinks, "[[:Файл:" .. entry.id .. ".png]]")
            end
            table.insert(result, mw.getCurrentFrame():preprocess(
                "{{Entity Sprite/Repeat|" .. table.concat(idLinks, " ") .. "|" .. group[1].id .. "}}"
            ))
        end
    end


    return table.concat(result, "\n")
local links = {}
 
for _, item in ipairs(states) do
if item.sprite and item.state then
table.insert(links, buildStateLink(baseUrl, item.sprite, item.state))
end
end
 
return table.concat(links, ", ")
end
end


local function generateTemplate(entry, param)
local function buildRepeatSpriteValue(baseUrl, entry)
    local spritePath = getSpritePath(entry)
local spritePath = getSpritePath(entry)
    if not entry.id or not spritePath then
if not spritePath then
        return nil
return ""
    end
end


    local state = getSpriteState(entry)
local pathLink = buildSpritePathLink(baseUrl, spritePath)
local states = getSpriteStates(entry)


    if param == "image" then
if states and #states > 0 and states[1].state and states[1].state ~= "" then
        local stateStr = ""
return pathLink .. " (" .. buildStateLink(baseUrl, spritePath, states[1].state) .. ")"
        if state then
end
            stateStr = " (state: " .. state .. ")"
        end
        return mw.getCurrentFrame():preprocess(
            "{{Entity Sprite/Image|" .. entry.id ..
            "|https://github.com/space-syndicate/space-station-14/blob/master/Resources/Textures/" ..
            spritePath .. stateStr .. "}}"
        )
    end


    return nil
return pathLink
end
 
local function generateRepeatTemplate(data, project, baseUrl)
local spriteGroups = {}
 
for id, entry in pairs(data) do
local key = buildEntryKey(entry)
 
spriteGroups[key] = spriteGroups[key] or {}
table.insert(spriteGroups[key], { id = id, entry = entry })
end
 
local result = {}
 
for _, group in pairs(spriteGroups) do
if #group > 1 then
local idLinks = {}
 
for _, obj in ipairs(group) do
table.insert(idLinks, buildFileLink(obj.id, project))
end
 
local firstId = group[1].id
local firstEntry = group[1].entry
local spriteValue = buildRepeatSpriteValue(baseUrl, firstEntry)
 
table.insert(result, mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
"|перенаправление=" .. JsonPaths.prefixFile(firstId) ..
"|id=" .. firstId ..
"|спрайт=" .. spriteValue ..
"}}"
))
end
end
 
return table.concat(result, "\n")
end
 
local function generateTemplate(id, entry, baseUrl, project)
local spritePath = getSpritePath(entry)
if not id or not spritePath then
return nil
end
 
local states = getSpriteStates(entry)
local stateStr = buildSpriteStateLinks(baseUrl, states)
 
return mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Image|файл=" .. JsonPaths.prefixFile(id) ..
"|id=" .. id ..
"|путь=" .. buildSpriteUrl(baseUrl, spritePath) ..
"|state=" .. stateStr ..
"}}"
)
end
end


function p.main(frame)
function p.main(frame)
    local action = frame.args[1]
local action = frame.args[1]
    local mode = frame.args[2]
local json = frame.args.json or "component/Sprite.json"
 
local project = JsonPaths.project()
local baseUrl = JsonPaths.git() .. "/Resources/Textures/"
 
local dataPage = JsonPaths.get(json)
local parentPage = JsonPaths.get("entity parent.json")
 
local spriteDataRaw = mw.loadData(dataPage)
local parentDataRaw = mw.loadData(parentPage)
 
local spriteData = normalizeData(spriteDataRaw)
local parentData = normalizeData(parentDataRaw)
 
if not spriteData or type(spriteData) ~= "table" then
return "Ошибка загрузки JSON: " .. dataPage
end
 
if not parentData or type(parentData) ~= "table" then
return "Ошибка загрузки JSON: " .. parentPage
end
 
local whitelistSet = buildSet(frame.args.whitelistParent)
local blacklistSet = buildSet(frame.args.blacklistParent)
local filteredData = filterSpriteData(spriteData, parentData, whitelistSet, blacklistSet, project)
 
if action == "repeat" then
return generateRepeatTemplate(filteredData, project, baseUrl)
elseif action == "image" then
local result = {}


    local dataPage
for id, entry in pairs(filteredData) do
    if mode == "item" then
local t = generateTemplate(id, entry, baseUrl, project)
        dataPage = "Модуль:IanComradeBot/prototypes/entity sprite/item.json/data"
if t then
    elseif mode == "structure" then
table.insert(result, t)
        dataPage = "Модуль:IanComradeBot/prototypes/entity sprite/structure.json/data"
end
    elseif mode == "mob" then
end
        dataPage = "Модуль:IanComradeBot/prototypes/entity sprite/mob.json/data"
    elseif mode == "other" then
        dataPage = "Модуль:IanComradeBot/prototypes/entity sprite/other.json/data"
    else
        dataPage = "Модуль:IanComradeBot/prototypes/entity sprite.json/data"
    end


    local spriteData = mw.loadData(dataPage)
return table.concat(result, "\n")
    if not spriteData or type(spriteData) ~= "table" then
end
        return "Ошибка: Невозможно загрузить данные из JSON (" .. dataPage .. ")."
    end


    if action == "repeat" then
return nil
        return generateRepeatTemplate(spriteData)
    elseif action == "image" or action == "path" then
        local result = {}
        for _, entry in pairs(spriteData) do
            local template = generateTemplate(entry, action)
            if template then
                table.insert(result, template)
            end
        end
        return table.concat(result, "\n")
    else
        return nil
    end
end
end


return p
return p