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

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


local cache = nil
local function normalizeSpritePath(path)
if mw.cache and mw.cache.new then
if path == nil then
    cache = mw.cache.new('EntitySpriteCache')
return nil
else
end
    cache = {
        get = function(key)
            return nil
        end,
        set = function(key, value)
        end
    }
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 function normalizeState(state)
        local i = 0
if state == nil then
        for _ in pairs(t) do
return nil
            i = i + 1
end
            if t[i] == nil then return false end
        end
        return true
    end


    if isArray(t1) and isArray(t2) then
state = mw.text.trim(tostring(state))
        if #t1 ~= #t2 then return false end
if state == "" then
        local matched = {}
return nil
        for _, v1 in ipairs(t1) do
end
            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
return state
        if t2[k] == nil or not deepEqual(v, t2[k]) then
end
            return false
        end
    end


    for k, _ in pairs(t2) do
-- Функция получения таблицы данных
        if t1[k] == nil then
local function getIdTable()
            return false
if type(spriteData) == "table" and type(spriteData.id) == "table" then
        end
return spriteData.id
    end
end
return nil
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 или переменными модуля
if entry.sprite then
local function loadData(filePath)
return normalizeSpritePath(entry.sprite)
    if cachedData then
end
        return cachedData
    end


    cachedData = cache:get('data')
if type(entry.layers) == "table" then
    dataById = cache:get('dataById')
for _, layer in ipairs(entry.layers) do
    if cachedData and dataById then
if layer and layer.sprite then
        return cachedData
return normalizeSpritePath(layer.sprite)
    end
end
end
end


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


    if cachedData and type(cachedData) == "table" then
-- Проверка visible
        dataById = {}
local function isLayerVisible(layer)
        for _, item in ipairs(cachedData) do
if not layer then
            dataById[tostring(item.id)] = item
return false
        end
end
        cache:set('data', cachedData)
return layer.visible ~= false
        cache:set('dataById', dataById)
end
    end


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


-- Создание индекса для путей спрайтов с кэшированием
if entry and type(entry.layers) == "table" then
local function createSpritePathIndex(data)
for _, layer in ipairs(entry.layers) do
    if cachedSpritePathIndex then
if isLayerVisible(layer) and layer.state then
        return cachedSpritePathIndex
table.insert(result, {
    end
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


    cachedSpritePathIndex = cache:get('spritePathIndex')
if #result == 0 and spritePath then
    if cachedSpritePathIndex then
table.insert(result, {
        return cachedSpritePathIndex
state = "icon",
    end
sprite = spritePath
})
end


    local index = {}
return (#result > 0) and result or nil
    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
local function findByPathAndState(data, targetPath, targetState)
local function generateRepeatTemplate(data)
for entityId, entry in pairs(data) do
    local spriteGroups = {}
if getSpritePath(entry) == targetPath then
local states = getSpriteStates(entry)
if states then
for _, item in ipairs(states) do
if normalizeState(item.state) == targetState then
return entityId
end
end
end
end
end


    for _, entry in ipairs(data) do
return nil
        local found = false
end
        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
local function findByPath(data, targetPath)
            spriteGroups[entry.id] = { entry }
for entityId, entry in pairs(data) do
        end
if getSpritePath(entry) == targetPath then
    end
return entityId
end
end


    local result = {}
return nil
    for _, group in pairs(spriteGroups) do
end
        if #group > 1 then
            local idLinks = {}
            for _, entry in ipairs(group) do
                table.insert(idLinks, "[[:Файл:" .. entry.id .. ".png]]")
            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")
-- Функция генерации шаблона по записи (mode: image, path, state)
end
function p.main(frame)
local mode = frame.args[1]
local id = frame.args[2]
local stateArg = frame.args[3]


-- Генерация шаблона для image и path
if not mode or not id then
local function generateTemplate(entry, param, secondaryParam, spritePathIndex)
return "Ошибка: отсутствует режим или ID"
    local spritePath = getSpritePath(entry)
end
    if not entry.id or not spritePath then
        return nil
    end


    if param == "image" then
local data = getIdTable()
        if secondaryParam then
if not data then
            if tostring(entry.id) == tostring(secondaryParam) then
return "Ошибка: неверный формат JSON"
                return spritePath
end
            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
if mode == "image" or mode == "state" then
end
local entry = data[id]
if not entry then
return "Ошибка: ID не найден"
end


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


    local spritePath = nil
local baseUrl = JsonPaths.git() .. "/Resources/Textures/"
    local path = params.Path
local links = {}


    local entry = nil
for _, item in ipairs(states) do
    if id and id ~= "" and dataById then
local spritePath = item.sprite
        entry = dataById[tostring(id)]
local stateName = item.state
    else
        for _, item in ipairs(data) do
            if tostring(item.id) == tostring(id) then
                entry = item
                break
            end
        end
    end


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


    if not path or path == "" then
return "(state: " .. table.concat(links, ", ") .. ")"
        path = "Resources/Textures/" .. (spritePath or "")
end
    end
end


    return mw.getCurrentFrame():preprocess(
if mode == "path" then
        "{{Файл\n" ..
local targetPath = normalizeSpritePath(id)
        "|Описание = " .. description .. "\n" ..
local targetState = normalizeState(stateArg)
        "|Id      = " .. id .. "\n" ..
        "|Сервера  = " .. servers .. "\n" ..
        "|Источник = " .. source .. "\n" ..
        "|Путь    = " .. path .. "\n" ..
        "|Теги    = " .. tags .. "\n" ..
        "}}\n"
    )
end


function p.main(frame)
if targetState then
    local param = frame.args[1]
local byState = findByPathAndState(data, targetPath, targetState)
    local secondaryParam = frame.args[2]
if byState then
return byState
end
end


    local data = loadData('User:IanComradeBot/prototypes/entity sprite.json')
local byPath = findByPath(data, targetPath)
    if not data or type(data) ~= 'table' then
if byPath then
        return 'Ошибка: Невозможно загрузить данные из JSON.'
return byPath
    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
        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

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

Документация
-- Загрузка данных
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 normalizeState(state)
	if state == nil then
		return nil
	end

	state = mw.text.trim(tostring(state))
	if state == "" then
		return nil
	end

	return state
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

local function findByPathAndState(data, targetPath, targetState)
	for entityId, entry in pairs(data) do
		if getSpritePath(entry) == targetPath then
			local states = getSpriteStates(entry)
			if states then
				for _, item in ipairs(states) do
					if normalizeState(item.state) == targetState then
						return entityId
					end
				end
			end
		end
	end

	return nil
end

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

	return nil
end

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

	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)
		local targetState = normalizeState(stateArg)

		if targetState then
			local byState = findByPathAndState(data, targetPath, targetState)
			if byState then
				return byState
			end
		end

		local byPath = findByPath(data, targetPath)
		if byPath then
			return byPath
		end

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

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

return p