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

Материал из Space Station 14 Вики
Нет описания правки
Нет описания правки
 
(не показано 11 промежуточных версий этого же участника)
Строка 1: Строка 1:
local p = {}
local p = {}
local JsonPaths = require('Module:JsonPaths')
local JsonPaths = require('Module:JsonPaths')
local prefix = JsonPaths.prefixFile()


local function normalizeSpritePath(path)
local function normalizeSpritePath(path)
Строка 139: Строка 138:
end
end


local function getParents(entry)
local function getParents(parentData, id)
if not entry then
if not parentData or type(parentData) ~= "table" or not id then
return nil
return nil
end
end


if type(entry.parents) == "table" then
local parents = parentData[id]
return entry.parents
if type(parents) ~= "table" then
return nil
end
end


if type(entry.parents) == "string" then
return parents
return splitCsv(entry.parents)
end
 
local function hasAnyParent(parents, set)
if not parents or not set then
return false
end
end


return nil
for _, parent in ipairs(parents) do
if set[parent] then
return true
end
end
 
return false
end
end


local function shouldIncludeEntry(entry, whitelistSet, blacklistSet)
local function shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData)
local parents = getParents(entry)
local parents = getParents(parentData, id)


if whitelistSet and not hasAnyParent(parents, whitelistSet) then
if whitelistSet and not hasAnyParent(parents, whitelistSet) then
Строка 169: Строка 179:
end
end


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


for id, entry in pairs(spriteData) do
for id, entry in pairs(spriteData) do
local protoEntry = prototypeData and prototypeData[id] or entry
if shouldIncludeEntry(id, whitelistSet, blacklistSet, parentData) then
 
if shouldIncludeEntry(protoEntry, whitelistSet, blacklistSet) then
if project == "" or JsonPaths.has(id, project) then
if project == "" or JsonPaths.has(id, project) then
result[id] = entry
result[id] = entry
Строка 183: Строка 191:


return result
return result
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 and not hasAnyParent(parents, whitelistSet) then
return false
end
if blacklistSet and hasAnyParent(parents, blacklistSet) then
return false
end
return true
end
end


local function buildFileLink(id, project)
local function buildFileLink(id, project)
return "[[:Файл:" .. prefix .. id .. ".png]]"
return "[[:Файл:" .. JsonPaths.prefixFile(id) .. ".png]]"
end
end


Строка 289: Строка 269:
table.insert(result, mw.getCurrentFrame():preprocess(
table.insert(result, mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
"|перенаправление=" .. prefix .. firstId ..
"|перенаправление=" .. JsonPaths.prefixFile(firstId) ..
"|id=" .. firstId ..
"|id=" .. firstId ..
"|спрайт=" .. spriteValue ..
"|спрайт=" .. spriteValue ..
Строка 310: Строка 290:


return mw.getCurrentFrame():preprocess(
return mw.getCurrentFrame():preprocess(
"{{Entity Sprite/Image|файл=" .. prefix .. id ..
"{{Entity Sprite/Image|файл=" .. JsonPaths.prefixFile(id) ..
"|id=" .. id ..
"|id=" .. id ..
"|путь=" .. buildSpriteUrl(baseUrl, spritePath) ..
"|путь=" .. buildSpriteUrl(baseUrl, spritePath) ..
Строка 320: Строка 300:
function p.main(frame)
function p.main(frame)
local action = frame.args[1]
local action = frame.args[1]
local json = frame.args.json or "prototype/sprite.json"
local json = frame.args.json or "component/Sprite.json"


local project = JsonPaths.project()
local project = JsonPaths.project()
Строка 326: Строка 306:


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


local spriteDataRaw = mw.loadData(dataPage)
local spriteDataRaw = mw.loadData(dataPage)
local prototypeDataRaw = mw.loadData(prototypesPage)
local parentDataRaw = mw.loadData(parentPage)


local spriteData = normalizeData(spriteDataRaw)
local spriteData = normalizeData(spriteDataRaw)
local prototypeData = normalizeData(prototypeDataRaw)
local parentData = normalizeData(parentDataRaw)


if not spriteData or type(spriteData) ~= "table" then
if not spriteData or type(spriteData) ~= "table" then
Строка 338: Строка 318:
end
end


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


local whitelistSet = buildSet(frame.args.whitelistParent)
local whitelistSet = buildSet(frame.args.whitelistParent)
local blacklistSet = buildSet(frame.args.blacklistParent)
local blacklistSet = buildSet(frame.args.blacklistParent)
local filteredData = filterSpriteData(spriteData, prototypeData, whitelistSet, blacklistSet, project)
local filteredData = filterSpriteData(spriteData, parentData, whitelistSet, blacklistSet, project)


if action == "repeat" then
if action == "repeat" then

Текущая версия от 15:31, 23 июня 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 normalizeData(data)
	if type(data) ~= "table" then
		return nil
	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

			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

local function getSpritePath(entry)
	if entry.sprite then
		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

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 buildStateLink(baseUrl, spritePath, state)
	local url = buildSpriteUrl(baseUrl, spritePath) .. "/" .. state .. ".png"
	return "[" .. url .. " " .. state .. "]"
end

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

	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

local function buildRepeatSpriteValue(baseUrl, entry)
	local spritePath = getSpritePath(entry)
	if not spritePath then
		return ""
	end

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

	if states and #states > 0 and states[1].state and states[1].state ~= "" then
		return pathLink .. " (" .. buildStateLink(baseUrl, spritePath, states[1].state) .. ")"
	end

	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

function p.main(frame)
	local action = frame.args[1]
	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 = {}

		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