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

Материал из Space Station 14 Вики
мНет описания правки
Нет описания правки
 
(не показано 29 промежуточных версий этого же участника)
Строка 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 buildEntryKey(entry)
                return false
local parts = {}
            end
 
        end
if entry.sprite then
        return true
table.insert(parts, "sprite=" .. normalizeSpritePath(entry.sprite))
    end
end
 
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
layerParts[#layerParts+1] = k .. "=" .. tostring(v)
end
 
table.sort(layerParts)
table.insert(layers, table.concat(layerParts, ","))
end
 
table.sort(layers)
table.insert(parts, "layers=" .. table.concat(layers, "|"))
end
 
return table.concat(parts, ";")
end
 
local function getSpritePath(entry)
return normalizeSpritePath(entry.sprite)
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 then
table.insert(result, {
state = tostring(layer.state or entry.state or ""),
sprite = normalizeSpritePath(layer.sprite or entry.sprite)
})
end
end
elseif entry.state and entry.sprite then
table.insert(result, {
state = tostring(entry.state or ""),
sprite = normalizeSpritePath(entry.sprite)
})
end
 
return (#result > 0) and result or nil
end
 
local function getPrefix(id, project)
if project ~= "" and JsonPaths.has(id, project) then
return project .. ":"
end
return ""
end
 
local function splitCsv(value)
local result = {}
 
if value == nil then
return nil
end


    for k, v in pairs(t1) do
value = mw.text.trim(tostring(value))
        if t2[k] == nil or not deepEqual(v, t2[k]) then
if value == "" then
            return false
return nil
        end
end
    end


    for k, v in pairs(t2) do
for part in mw.text.gsplit(value, ",", true) do
        if t1[k] == nil or not deepEqual(v, t1[k]) then
local item = mw.text.trim(part)
            return false
if item ~= "" then
        end
table.insert(result, item)
    end
end
end


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


local function getInsensitiveKey(t, target)
local function buildSet(value)
    target = target:lower()
local list = splitCsv(value)
    for k, v in pairs(t) do
if not list then
        if type(k) == "string" and k:lower() == target then
return nil
            return v
end
        end
 
    end
local set = {}
    return nil
for _, item in ipairs(list) do
set[item] = true
end
 
return set
end
end


local function getSpritePath(entry)
local function getParents(entry)
    local spriteField = getInsensitiveKey(entry, "Sprite")
if not entry then
    local iconField = getInsensitiveKey(entry, "Icon")
return nil
end
 
if type(entry.parents) == "table" then
return entry.parents
end
 
if type(entry.parents) == "string" then
return splitCsv(entry.parents)
end


    if spriteField and spriteField.sprite then
return nil
        return spriteField.sprite
    elseif iconField and iconField.sprite then
        return iconField.sprite
    elseif spriteField and spriteField.layers then
        for _, layer in pairs(spriteField.layers) do
            if layer.sprite then
                return layer.sprite
            end
        end
    end
    return nil
end
end


local function getSpriteState(entry)
local function hasAnyParent(parents, set)
    local spriteBlock = getInsensitiveKey(entry, "Sprite")
if not parents or not set then
    if spriteBlock then
return false
        if spriteBlock.state then
end
            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 _, parent in ipairs(parents) do
    if iconBlock and iconBlock.state then
if set[parent] then
        return iconBlock.state
return true
    end
end
end


    return nil
return false
end
end


local function generateRepeatTemplate(data)
local function shouldIncludeEntry(entry, whitelistSet, blacklistSet)
    local spriteGroups = {}
local parents = getParents(entry)
 
if whitelistSet then
if not hasAnyParent(parents, whitelistSet) then
return false
end
end
 
if blacklistSet and hasAnyParent(parents, blacklistSet) then
return false
end
 
return true
end


    for _, entry in pairs(data) do
local function filterSpriteData(spriteData, prototypeData, whitelistSet, blacklistSet)
        local found = false
local result = {}
        for _, group in pairs(spriteGroups) do
            if deepEqual(getInsensitiveKey(entry, "Sprite"), getInsensitiveKey(group[1], "Sprite")) and
              deepEqual(entry.EntityStorageVisuals, group[1].EntityStorageVisuals) and
              deepEqual(getInsensitiveKey(entry, "Icon"), getInsensitiveKey(group[1], "Icon")) then
                table.insert(group, entry)
                found = true
                break
            end
        end


        if not found then
for id, entry in pairs(spriteData) do
            table.insert(spriteGroups, {entry})
local protoEntry = prototypeData and prototypeData[id] or entry
        end
    end


    local result = {}
if shouldIncludeEntry(protoEntry, whitelistSet, blacklistSet) then
    for _, group in pairs(spriteGroups) do
result[id] = entry
        if #group > 1 then
end
            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")
return result
end
end


local function generateTemplate(entry, param)
local function generateRepeatTemplate(data, project)
    local spritePath = getSpritePath(entry)
local spriteGroups = {}
    if not entry.id or not spritePath then
 
        return nil
for id, entry in pairs(data) do
    end
local key = buildEntryKey(entry)


    local state = getSpriteState(entry)
spriteGroups[key] = spriteGroups[key] or {}
table.insert(spriteGroups[key], { id = id, entry = entry })
end


    if param == "image" then
local result = {}
        local stateStr = ""
        if state then
            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
for _, group in pairs(spriteGroups) do
if #group > 1 then
local idLinks = {}
for _, obj in ipairs(group) do
local id = obj.id
local prefix = getPrefix(id, project)
table.insert(idLinks, "[[:Файл:" .. prefix .. id .. ".png]]")
end
local firstId = group[1].id
local prefix = getPrefix(firstId, project)
table.insert(result, mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Repeat|спрайты=" .. table.concat(idLinks, " ") ..
"|перенаправление=" .. prefix .. firstId ..
"|id=" .. firstId ..
"}}"
))
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 prefix = getPrefix(id, project)
 
local states = getSpriteStates(entry)
local stateStr = ""
 
if states then
local links = {}
for _, item in ipairs(states) do
if item.sprite and item.state then
local url = baseUrl .. item.sprite .. "/" .. item.state .. ".png"
table.insert(links, "[" .. url .. " " .. item.state .. "]")
end
end
stateStr = table.concat(links, ", ")
end
 
return mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Image|файл=" .. prefix .. id ..
"|id=" .. id ..
"|путь=" .. 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 "sprite_entity.json"
 
local project = JsonPaths.project()
local baseUrl = JsonPaths.git() .. "/Resources/Textures/"
 
local dataPage = JsonPaths.get(json)
local prototypesPage = JsonPaths.get("entity prototypes.json")
 
local spriteData = mw.loadData(dataPage)
local prototypeData = mw.loadData(prototypesPage)
 
if not spriteData or type(spriteData) ~= "table" then
return "Ошибка загрузки JSON: " .. dataPage
end
 
if not prototypeData or type(prototypeData) ~= "table" then
return "Ошибка загрузки JSON: " .. prototypesPage
end
 
local whitelistSet = buildSet(frame.args.whitelistParent)
local blacklistSet = buildSet(frame.args.blacklistParent)
 
local filteredData = filterSpriteData(spriteData, prototypeData, whitelistSet, blacklistSet)
 
if action == "repeat" then
return generateRepeatTemplate(filteredData, project)
 
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

Текущая версия от 03:10, 22 марта 2026

Для документации этого модуля может быть создана страница Модуль:Entity Sprite/all/doc

local p = {}
local JsonPaths = require('Module:JsonPaths')

local function normalizeSpritePath(path)
	if path == nil then
		return nil
	end

	path = mw.text.trim(tostring(path))
	path = path:gsub("^/Textures/?", "")

	return path
end

local function buildEntryKey(entry)
	local parts = {}

	if entry.sprite then
		table.insert(parts, "sprite=" .. normalizeSpritePath(entry.sprite))
	end

	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
				layerParts[#layerParts+1] = k .. "=" .. tostring(v)
			end

			table.sort(layerParts)
			table.insert(layers, table.concat(layerParts, ","))
		end

		table.sort(layers) 
		table.insert(parts, "layers=" .. table.concat(layers, "|"))
	end

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

local function getSpritePath(entry)
	return normalizeSpritePath(entry.sprite)
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 then
				table.insert(result, {
					state = tostring(layer.state or entry.state or ""),
					sprite = normalizeSpritePath(layer.sprite or entry.sprite)
				})
			end
		end
	elseif entry.state and entry.sprite then
		table.insert(result, {
			state = tostring(entry.state or ""),
			sprite = normalizeSpritePath(entry.sprite)
		})
	end

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

local function getPrefix(id, project)
	if project ~= "" and JsonPaths.has(id, project) then
		return project .. ":"
	end
	return ""
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(entry)
	if not entry then
		return nil
	end

	if type(entry.parents) == "table" then
		return entry.parents
	end

	if type(entry.parents) == "string" then
		return splitCsv(entry.parents)
	end

	return nil
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(entry, whitelistSet, blacklistSet)
	local parents = getParents(entry)

	if whitelistSet then
		if not hasAnyParent(parents, whitelistSet) then
			return false
		end
	end

	if blacklistSet and hasAnyParent(parents, blacklistSet) then
		return false
	end

	return true
end

local function filterSpriteData(spriteData, prototypeData, whitelistSet, blacklistSet)
	local result = {}

	for id, entry in pairs(spriteData) do
		local protoEntry = prototypeData and prototypeData[id] or entry

		if shouldIncludeEntry(protoEntry, whitelistSet, blacklistSet) then
			result[id] = entry
		end
	end

	return result
end

local function generateRepeatTemplate(data, project)
	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
				local id = obj.id
				local prefix = getPrefix(id, project)
	
				table.insert(idLinks, "[[:Файл:" .. prefix .. id .. ".png]]")
			end
	
			local firstId = group[1].id
			local prefix = getPrefix(firstId, project)
	
			table.insert(result, mw.getCurrentFrame():preprocess(
				"{{Entity Sprite/Repeat|спрайты=" .. table.concat(idLinks, " ") ..
				"|перенаправление=" .. prefix .. firstId ..
				"|id=" .. firstId ..
				"}}"
			))
		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 prefix = getPrefix(id, project)

	local states = getSpriteStates(entry)
	local stateStr = ""

	if states then
		local links = {}
		for _, item in ipairs(states) do
			if item.sprite and item.state then
				local url = baseUrl .. item.sprite .. "/" .. item.state .. ".png"
				table.insert(links, "[" .. url .. " " .. item.state .. "]")
			end
		end
		stateStr = table.concat(links, ", ")
	end

	return mw.getCurrentFrame():preprocess(
		"{{Entity Sprite/Image|файл=" .. prefix .. id ..
		"|id=" .. id ..
		"|путь=" .. baseUrl .. spritePath ..
		"|state=" .. stateStr ..
		"}}"
	)
end

function p.main(frame)
	local action = frame.args[1]
	local json = frame.args.json or "sprite_entity.json"

	local project = JsonPaths.project()
	local baseUrl = JsonPaths.git() .. "/Resources/Textures/"

	local dataPage = JsonPaths.get(json)
	local prototypesPage = JsonPaths.get("entity prototypes.json")

	local spriteData = mw.loadData(dataPage)
	local prototypeData = mw.loadData(prototypesPage)

	if not spriteData or type(spriteData) ~= "table" then
		return "Ошибка загрузки JSON: " .. dataPage
	end

	if not prototypeData or type(prototypeData) ~= "table" then
		return "Ошибка загрузки JSON: " .. prototypesPage
	end

	local whitelistSet = buildSet(frame.args.whitelistParent)
	local blacklistSet = buildSet(frame.args.blacklistParent)

	local filteredData = filterSpriteData(spriteData, prototypeData, whitelistSet, blacklistSet)

	if action == "repeat" then
		return generateRepeatTemplate(filteredData, project)

	elseif action == "image" then
		local result = {}

		for id, entry in pairs(filteredData) do
			local t = generateTemplate(id, entry, baseUrl, project)
			if t then
				table.insert(result, t)
			end
		end

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

	return nil
end

return p