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

Материал из Space Station 14 Вики
мНет описания правки
Нет описания правки
 
(не показано 59 промежуточных версий этого же участника)
Строка 1: Строка 1:
-- Загрузка данных
local JsonPaths = require('Module:JsonPaths')
local spriteData = mw.loadData(JsonPaths.get("prototype/sprite.json"))
local p = {}
local p = {}


local cache = mw.cache.new('EntitySpriteCache')
local function normalizeSpritePath(path)
if path == nil then
return nil
end


-- Переменные для кэширования в пределах модуля
path = mw.text.trim(tostring(path))
local cachedData = nil
path = path:gsub("^/Textures/?", "")
local cachedSpritePathIndex = nil
local dataById = nil


-- Функция глубокого сравнения таблиц
return path
local function deepEqual(t1, t2)
end
    if t1 == t2 then return true end
    if type(t1) ~= "table" or type(t2) ~= "table" then return false end


    local function isArray(t)
-- Функция получения таблицы данных
        local i = 0
local function getIdTable()
        for _ in pairs(t) do
if type(spriteData) == "table" and type(spriteData.id) == "table" then
            i = i + 1
return spriteData.id
            if t[i] == nil then return false end
end
        end
return nil
        return true
end
    end
 
    if isArray(t1) and isArray(t2) then
        if #t1 ~= #t2 then return false end
        local matched = {}
        for _, v1 in ipairs(t1) do
            local found = false
            for j, v2 in ipairs(t2) do
                if not matched[j] and deepEqual(v1, v2) then
                    matched[j] = true
                    found = true
                    break
                end
            end
            if not found then return false end
        end
        return true
    end
 
    for k, v in pairs(t1) do
        if t2[k] == nil or not deepEqual(v, t2[k]) then
            return false
        end
    end
 
    for k, _ in pairs(t2) do
        if t1[k] == nil then
            return false
        end
    end


    return true
-- Функция для получения таблицы данных
function p.getData()
return getIdTable() or {}
end
end


-- Функция получения пути спрайта из записи
-- Функция получения пути спрайта:
-- 1) сначала entry.sprite
-- 2) потом первый layers[*].sprite
local function getSpritePath(entry)
local function getSpritePath(entry)
    if entry.Sprite and entry.Sprite.sprite then
if not entry then
        return entry.Sprite.sprite
return nil
    elseif entry.Icon and entry.Icon.sprite then
end
        return entry.Icon.sprite
    elseif entry.Sprite and entry.Sprite.layers then
        for _, layer in ipairs(entry.Sprite.layers) do
            if layer.sprite then
                return layer.sprite
            end
        end
    end
    return nil
end
 
-- Загрузка JSON-данных с кэшированием через mw.cache
local function loadData(filePath)
    if cachedData then
        return cachedData
    end
 
    cachedData = cache:get('data')
    dataById = cache:get('dataById')
    if cachedData and dataById then
        return cachedData
    end


    local page = mw.title.new(filePath)
if entry.sprite then
    local content = page and page:getContent()
return normalizeSpritePath(entry.sprite)
    cachedData = content and mw.text.jsonDecode(content) or nil
end


    if cachedData and type(cachedData) == "table" then
if type(entry.layers) == "table" then
        dataById = {}
for _, layer in ipairs(entry.layers) do
        for _, item in ipairs(cachedData) do
if layer and layer.sprite then
            dataById[tostring(item.id)] = item
return normalizeSpritePath(layer.sprite)
        end
end
        cache:set('data', cachedData)
end
        cache:set('dataById', dataById)
end
    end


    return cachedData
return nil
end
end


-- Создание индекса для путей спрайтов с кэшированием
-- Проверка visible
local function createSpritePathIndex(data)
local function isLayerVisible(layer)
    if cachedSpritePathIndex then
if not layer then
        return cachedSpritePathIndex
return false
    end
end
 
return layer.visible ~= false
    cachedSpritePathIndex = cache:get('spritePathIndex')
    if cachedSpritePathIndex then
        return cachedSpritePathIndex
    end
 
    local index = {}
    for _, entry in ipairs(data) do
        local spritePath = getSpritePath(entry)
        if spritePath then
            index[spritePath] = entry.id
        end
    end
    cachedSpritePathIndex = index
    cache:set('spritePathIndex', cachedSpritePathIndex)
    return cachedSpritePathIndex
end
end


-- Генерация шаблона repeat
-- Функция получения списка состояний с учётом переопределяющего sprite в слое
local function generateRepeatTemplate(data)
local function getSpriteStates(entry)
    local spriteGroups = {}
local result = {}
 
local spritePath = getSpritePath(entry)
    for _, entry in ipairs(data) do
        local found = false
        for key, group in pairs(spriteGroups) do
            if deepEqual(entry.Sprite, group[1].Sprite) and
              deepEqual(entry.EntityStorageVisuals, group[1].EntityStorageVisuals) and
              deepEqual(entry.Icon, group[1].Icon) then
                table.insert(group, entry)
                found = true
                break
            end
        end


        if not found then
if entry and type(entry.layers) == "table" then
            spriteGroups[entry.id] = { entry }
for _, layer in ipairs(entry.layers) do
        end
if isLayerVisible(layer) and layer.state then
    end
table.insert(result, {
state = tostring(layer.state),
sprite = normalizeSpritePath(layer.sprite or spritePath)
})
end
end
elseif entry and entry.state and spritePath then
table.insert(result, {
state = tostring(entry.state),
sprite = spritePath
})
end


    local result = {}
if #result == 0 and spritePath then
    for _, group in pairs(spriteGroups) do
table.insert(result, {
        if #group > 1 then
state = "icon",
            local idLinks = {}
sprite = spritePath
            for _, entry in ipairs(group) do
})
                table.insert(idLinks, "[[:Файл:" .. entry.id .. ".png]]")
end
            end
            local firstId = group[1].id
            table.insert(result, mw.getCurrentFrame():preprocess("{{Entity Sprite/Repeat|" .. table.concat(idLinks, " ") .. "|" .. firstId .. "}}"))
        end
    end


    return table.concat(result, "\n")
return (#result > 0) and result or nil
end
end


-- Генерация шаблона для image и path
-- Функция генерации шаблона по записи (mode: image, path, state)
local function generateTemplate(entry, param, secondaryParam, spritePathIndex)
function p.main(frame)
    local spritePath = getSpritePath(entry)
local mode = frame.args[1]
    if not entry.id or not spritePath then
local id = frame.args[2]
        return nil
    end


    if param == "image" then
if not mode or not id then
        if secondaryParam then
return "Ошибка: отсутствует режим или ID"
            if tostring(entry.id) == tostring(secondaryParam) then
end
                return spritePath
            end
            return nil
        else
            return mw.getCurrentFrame():preprocess("{{Entity Sprite/Image|" .. entry.id .. "|" .. spritePath .. "}}")
        end
    elseif param == "path" then
        if secondaryParam then
            local id = spritePathIndex[secondaryParam]
            if id then
                return id
            end
            return nil
        else
            return mw.getCurrentFrame():preprocess("{{Entity Sprite/Path|" .. entry.id .. "|" .. spritePath .. "}}")
        end
    end


    return nil
local data = getIdTable()
end
if not data then
return "Ошибка: неверный формат JSON"
end


-- Генерация шаблона по умолчанию
if mode == "image" or mode == "state" then
local function generateDefaultTemplate(data, params)
local entry = data[id]
    local id = params.Id
if not entry then
    local description = params.Description or ""
return "Ошибка: ID не найден"
    local servers = params.Servers or ""
end
    local source = params.Source or ""
    local tags = params.Tags or ""


    local spritePath = nil
if mode == "image" then
    local path = params.Path
local sprite = getSpritePath(entry)
return sprite or "Ошибка: спрайт не найден"
elseif mode == "state" then
local states = getSpriteStates(entry)
if not states then
return ""
end


    local entry = nil
local baseUrl = JsonPaths.git() .. "/Resources/Textures/"
    if id and id ~= "" and dataById then
local links = {}
        entry = dataById[tostring(id)]
    else
        -- Если индекс по ID не создан, перебираем данные
        for _, item in ipairs(data) do
            if tostring(item.id) == tostring(id) then
                entry = item
                break
            end
        end
    end


    if entry then
for _, item in ipairs(states) do
        spritePath = getSpritePath(entry)
local spritePath = item.sprite
        if not spritePath then
local stateName = item.state
            return ""
        end
    end


    if not path or path == "" then
if spritePath then
        path = "Resources/Textures/" .. (spritePath or "")
local url = baseUrl .. normalizeSpritePath(spritePath) .. "/" .. stateName .. ".png"
    end
table.insert(links, "[" .. url .. " " .. stateName .. "]")
else
table.insert(links, stateName .. " Error: sprite not found")
end
end


    return mw.getCurrentFrame():preprocess(
return "(state: " .. table.concat(links, ", ") .. ")"
        "{{Файл\n" ..
end
        "|Описание = " .. description .. "\n" ..
end
        "|Id      = " .. id .. "\n" ..
        "|Сервера  = " .. servers .. "\n" ..
        "|Источник = " .. source .. "\n" ..
        "|Путь    = " .. path .. "\n" ..
        "|Теги    = " .. tags .. "\n" ..
        "}}\n"
    )
end


function p.main(frame)
if mode == "path" then
    local param = frame.args[1]
local targetPath = normalizeSpritePath(id)
    local secondaryParam = frame.args[2]


    local data = loadData('User:IanComradeBot/prototypes/entity sprite.json')
for entityId, entry in pairs(data) do
    if not data or type(data) ~= 'table' then
if getSpritePath(entry) == targetPath then
        return 'Ошибка: Невозможно загрузить данные из JSON.'
return entityId
    end
end
end


    local spritePathIndex = createSpritePathIndex(data)
return "Ошибка: путь не найден"
end


    if param == "repeat" then
return "Ошибка: неизвестный режим"
        return generateRepeatTemplate(data)
    elseif param == "path" and secondaryParam then
        for _, entry in ipairs(data) do
            local template = generateTemplate(entry, param, secondaryParam, spritePathIndex)
            if template then
                return template
            end
        end
        return nil
    elseif param == "image" and secondaryParam then
        -- Используем индекс по ID, чтобы не перебирать весь массив
        if dataById and dataById[tostring(secondaryParam)] then
            local entry = dataById[tostring(secondaryParam)]
            return getSpritePath(entry) or "Ошибка: Спрайт не найден."
        else
            return "Ошибка: ID не найден."
        end
    elseif param == "image" or param == "path" then
        local result = {}
        for _, entry in ipairs(data) do
            local template = generateTemplate(entry, param, secondaryParam, spritePathIndex)
            if template then
                table.insert(result, template)
            end
        end
        return table.concat(result, "\n")
    else
        return generateDefaultTemplate(data, frame.args)
    end
end
end


return p
return p

Текущая версия от 04:35, 23 марта 2026

Шаблон:Entity Sprite


-- Загрузка данных
local JsonPaths = require('Module:JsonPaths')
local spriteData = mw.loadData(JsonPaths.get("prototype/sprite.json"))

local p = {}

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 getIdTable()
	if type(spriteData) == "table" and type(spriteData.id) == "table" then
		return spriteData.id
	end
	return nil
end

-- Функция для получения таблицы данных
function p.getData()
	return getIdTable() or {}
end

-- Функция получения пути спрайта:
-- 1) сначала entry.sprite
-- 2) потом первый layers[*].sprite
local function getSpritePath(entry)
	if not entry then
		return nil
	end

	if entry.sprite then
		return normalizeSpritePath(entry.sprite)
	end

	if type(entry.layers) == "table" then
		for _, layer in ipairs(entry.layers) do
			if layer and layer.sprite then
				return normalizeSpritePath(layer.sprite)
			end
		end
	end

	return nil
end

-- Проверка visible
local function isLayerVisible(layer)
	if not layer then
		return false
	end
	return layer.visible ~= false
end

-- Функция получения списка состояний с учётом переопределяющего sprite в слое
local function getSpriteStates(entry)
	local result = {}
	local spritePath = getSpritePath(entry)

	if entry and type(entry.layers) == "table" then
		for _, layer in ipairs(entry.layers) do
			if isLayerVisible(layer) and layer.state then
				table.insert(result, {
					state = tostring(layer.state),
					sprite = normalizeSpritePath(layer.sprite or spritePath)
				})
			end
		end
	elseif entry and entry.state and spritePath then
		table.insert(result, {
			state = tostring(entry.state),
			sprite = spritePath
		})
	end

	if #result == 0 and spritePath then
		table.insert(result, {
			state = "icon",
			sprite = spritePath
		})
	end

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

-- Функция генерации шаблона по записи (mode: image, path, state)
function p.main(frame)
	local mode = frame.args[1]
	local id = frame.args[2]

	if not mode or not id then
		return "Ошибка: отсутствует режим или ID"
	end

	local data = getIdTable()
	if not data then
		return "Ошибка: неверный формат JSON"
	end

	if mode == "image" or mode == "state" then
		local entry = data[id]
		if not entry then
			return "Ошибка: ID не найден"
		end

		if mode == "image" then
			local sprite = getSpritePath(entry)
			return sprite or "Ошибка: спрайт не найден"
		elseif mode == "state" then
			local states = getSpriteStates(entry)
			if not states then
				return ""
			end

			local baseUrl = JsonPaths.git() .. "/Resources/Textures/"
			local links = {}

			for _, item in ipairs(states) do
				local spritePath = item.sprite
				local stateName = item.state

				if spritePath then
					local url = baseUrl .. normalizeSpritePath(spritePath) .. "/" .. stateName .. ".png"
					table.insert(links, "[" .. url .. " " .. stateName .. "]")
				else
					table.insert(links, stateName .. " Error: sprite not found")
				end
			end

			return "(state: " .. table.concat(links, ", ") .. ")"
		end
	end

	if mode == "path" then
		local targetPath = normalizeSpritePath(id)

		for entityId, entry in pairs(data) do
			if getSpritePath(entry) == targetPath then
				return entityId
			end
		end

		return "Ошибка: путь не найден"
	end

	return "Ошибка: неизвестный режим"
end

return p