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

мНет описания правки
Нет описания правки
 
(не показано 48 промежуточных версий этого же участника)
Строка 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
local function normalizeData(data)
                return false
if type(data) ~= "table" then
            end
return nil
        end
end
        return true
 
    end
if type(data.id) == "table" then
return data.id
end
 
return data
end
 
local function buildEntryKey(entry)
local parts = {}
 
local function addField(name, value)
if value ~= nil then
table.insert(parts, name .. "=" .. tostring(value))
end
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


    for k, v in pairs(t1) do
table.sort(layerParts)
        if t2[k] == nil or not deepEqual(v, t2[k]) then
table.insert(layers, table.concat(layerParts, ","))
            return false
end
        end
    end


    for k, v in pairs(t2) do
table.sort(layers)
        if t1[k] == nil or not deepEqual(v, t1[k]) then
table.insert(parts, "layers=" .. table.concat(layers, "|"))
            return false
end
        end
    end


    return true
table.sort(parts)
return table.concat(parts, ";")
end
end


local function findFieldInsensitive(tbl, fieldName)
local function getSpriteStates(entry)
    for key, value in pairs(tbl) do
local result = {}
        if type(key) == "string" and mw.ustring.lower(key) == mw.ustring.lower(fieldName) then
 
            return value
if entry.layers and type(entry.layers) == "table" then
        end
for _, layer in ipairs(entry.layers) do
    end
if layer.visible ~= false and layer.state then
    return nil
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 iconField = findFieldInsensitive(entry, "Icon")
if entry.sprite then
    local spriteField = findFieldInsensitive(entry, "Sprite")
return normalizeSpritePath(entry.sprite)
   
end
    if iconField and iconField.sprite then
 
        return iconField.sprite
if entry.layers and type(entry.layers) == "table" then
    elseif spriteField and spriteField.sprite then
for _, layer in ipairs(entry.layers) do
        return spriteField.sprite
if layer.sprite then
    elseif spriteField and spriteField.layers then
return normalizeSpritePath(layer.sprite)
        for _, layer in pairs(spriteField.layers) do
end
            if layer.sprite then
end
                return layer.sprite
end
            end
 
        end
return nil
    end
    return nil
end
end


local function isStateFirstKey(layer)
local function splitCsv(value)
    for k, _ in pairs(layer) do
local result = {}
        return k == "state"
 
    end
if value == nil then
    return false
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
end


local function getSpriteStates(entry)
local function getParents(parentData, id)
    local result = {}
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
 
local function shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData)
local parents = getParents(parentData, id)
 
if whitelistSet and not hasAnyParent(parents, whitelistSet) then
return false
end
 
if blacklistSet and hasAnyParent(parents, blacklistSet) then
return false
end
 
return true
end
 
local function filterSpriteData(spriteData, parentData, whitelistSet, blacklistSet, project)
local result = {}
 
for id, entry in pairs(spriteData) do
if shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData) then
if project == "" or JsonPaths.has(id, project) then
result[id] = entry
end
end
end
 
return result
end
 
local function buildFileLink(id, project)
return "[[:Файл:" .. JsonPaths.prefixFile(id) .. ".png]]"
end
 
local function buildSpriteUrl(baseUrl, spritePath)
return baseUrl .. spritePath
end
 
local function buildSpritePathLink(baseUrl, spritePath)
local url = buildSpriteUrl(baseUrl, spritePath)
return "[" .. url .. " " .. spritePath .. "]"
end


    local function addState(state, sprite)
local function buildStateLink(baseUrl, spritePath, state)
        table.insert(result, { state = state, sprite = sprite })
local url = buildSpriteUrl(baseUrl, spritePath) .. "/" .. state .. ".png"
    end
return "[" .. url .. " " .. state .. "]"
end


    local spritePath = getSpritePath(entry)
local function buildSpriteStateLinks(baseUrl, states)
if not states or #states == 0 then
return ""
end


    local iconBlock = findFieldInsensitive(entry, "Icon")
local links = {}
    local spriteBlock = findFieldInsensitive(entry, "Sprite")


    if iconBlock and iconBlock.state then
for _, item in ipairs(states) do
        addState(iconBlock.state, iconBlock.sprite or spritePath)
if item.sprite and item.state then
    else
table.insert(links, buildStateLink(baseUrl, item.sprite, item.state))
        if spriteBlock and spriteBlock.layers then
end
            for _, layer in ipairs(spriteBlock.layers) do
end
                if layer.visible ~= false then
                    local stateName = layer.state or (iconBlock and iconBlock.state) or "icon"
                    local s = layer.sprite or (iconBlock and iconBlock.sprite) or spritePath
                    addState(stateName, s)
                    break
                end
            end
        elseif spriteBlock and spriteBlock.state then
            addState(spriteBlock.state, spriteBlock.sprite or spritePath)
        end
    end


    if spriteBlock and spriteBlock.layers then
return table.concat(links, ", ")
        for _, layer in ipairs(spriteBlock.layers) do
end
            local alreadyAdded = false
            for _, r in ipairs(result) do
                local layerState = layer.state or "icon"
                if r.state == layerState then
                    alreadyAdded = true
                    break
                end
            end


            if not alreadyAdded and layer.visible ~= false then
local function buildRepeatSpriteValue(baseUrl, entry)
                local stateName = layer.state or "icon"
local spritePath = getSpritePath(entry)
                local s = layer.sprite or (iconBlock and iconBlock.sprite) or spritePath
if not spritePath then
return ""
end


                if s then
local pathLink = buildSpritePathLink(baseUrl, spritePath)
                    addState(stateName, s)
local states = getSpriteStates(entry)
                end
            end
        end
    end


    if #result == 0 and (iconBlock and (iconBlock.sprite or iconBlock.state) or spritePath) then
if states and #states > 0 and states[1].state and states[1].state ~= "" then
        local s = (iconBlock and iconBlock.sprite) or spritePath
return pathLink .. " (" .. buildStateLink(baseUrl, spritePath, states[1].state) .. ")"
        addState("icon", s)
end
    end


    return (#result > 0) and result or nil
return pathLink
end
end


local function generateRepeatTemplate(data)
local function generateRepeatTemplate(data, project, baseUrl)
    local spriteGroups = {}
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 _, entry in pairs(data) do
for _, obj in ipairs(group) do
        local found = false
table.insert(idLinks, buildFileLink(obj.id, project))
        for _, group in pairs(spriteGroups) do
end
            if deepEqual(findFieldInsensitive(entry, "Sprite"), findFieldInsensitive(group[1], "Sprite")) and
              deepEqual(entry.EntityStorageVisuals, group[1].EntityStorageVisuals) and
              deepEqual(findFieldInsensitive(entry, "Icon"), findFieldInsensitive(group[1], "Icon")) then
                table.insert(group, entry)
                found = true
                break
            end
        end


        if not found then
local firstId = group[1].id
            table.insert(spriteGroups, {entry})
local firstEntry = group[1].entry
        end
local spriteValue = buildRepeatSpriteValue(baseUrl, firstEntry)
    end


    local result = {}
table.insert(result, mw.getCurrentFrame():preprocess(
    for _, group in pairs(spriteGroups) do
"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
        if #group > 1 then
"|перенаправление=" .. JsonPaths.prefixFile(firstId) ..
            local idLinks = {}
"|id=" .. firstId ..
            for _, entry in pairs(group) do
"|спрайт=" .. spriteValue ..
                table.insert(idLinks, "[[:Файл:" .. entry.id .. ".png]]")
"}}"
            end
))
            table.insert(result, mw.getCurrentFrame():preprocess(
end
                "{{Entity Sprite/Repeat|" .. table.concat(idLinks, " ") .. "|" .. group[1].id .. "}}"
end
            ))
        end
    end


    return table.concat(result, "\n")
return table.concat(result, "\n")
end
end


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


    if param == "image" then
local states = getSpriteStates(entry)
        local states = getSpriteStates(entry)
local stateStr = buildSpriteStateLinks(baseUrl, states)
        local stateStr = ""
        if states then
            local baseUrl = "https://github.com/space-syndicate/space-station-14/blob/master/Resources/Textures/"
            local links = {}
            for _, item in ipairs(states) do
                local spritePath = item.sprite
                local stateName = item.state
                local url = baseUrl .. spritePath .. "/" .. stateName .. ".png"
                table.insert(links, "[" .. url .. " " .. stateName .. "]")
            end
            stateStr = table.concat(links, ", ")
        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 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" 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