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

Материал из Space Station 14 Вики
Нет описания правки
Нет описания правки
Строка 11: Строка 11:


return path
return path
end
local function getSpritePath(entry)
return entry and normalizeSpritePath(entry.sprite) or nil
end
local function getSpriteStates(entry)
local result = {}
if entry and entry.layers and type(entry.layers) == "table" then
for _, layer in ipairs(entry.layers) do
if layer.visible ~= false and layer.state then
result[#result + 1] = {
state = tostring(layer.state),
sprite = normalizeSpritePath(layer.sprite or entry.sprite)
}
end
end
elseif entry and entry.state and entry.sprite then
result[#result + 1] = {
state = tostring(entry.state),
sprite = normalizeSpritePath(entry.sprite)
}
end
return (#result > 0) and result or nil
end
local function getPrimaryState(entry)
local states = getSpriteStates(entry)
if states and states[1] and states[1].state and states[1].state ~= "" then
return states[1].state
end
if entry and entry.state then
return tostring(entry.state)
end
return nil
end
local function buildSpriteLink(baseUrl, spritePath)
return "[" .. baseUrl .. spritePath .. " " .. spritePath .. "]"
end
local function buildStateLink(baseUrl, spritePath, stateName)
return "[" .. baseUrl .. spritePath .. "/" .. stateName .. ".png " .. stateName .. "]"
end
local function buildStateLinks(entry, baseUrl)
local spritePath = getSpritePath(entry)
local states = getSpriteStates(entry)
if not spritePath or not states then
return nil
end
local links = {}
for _, item in ipairs(states) do
if item.sprite and item.state then
links[#links + 1] = buildStateLink(baseUrl, item.sprite, item.state)
end
end
return (#links > 0) and links or nil
end
local function renderTemplate(template)
return mw.getCurrentFrame():preprocess(template)
end
end


Строка 18: Строка 89:
local function addField(name, value)
local function addField(name, value)
if value ~= nil then
if value ~= nil then
table.insert(parts, name .. "=" .. tostring(value))
parts[#parts + 1] = name .. "=" .. tostring(value)
end
end
end
end


addField("sprite", normalizeSpritePath(entry.sprite))
addField("sprite", getSpritePath(entry))
addField("state", entry.state)
addField("state", entry.state)
addField("scale", entry.scale)
addField("scale", entry.scale)
Строка 41: Строка 112:


table.sort(layerParts)
table.sort(layerParts)
table.insert(layers, table.concat(layerParts, ","))
layers[#layers + 1] = table.concat(layerParts, ",")
end
end


table.sort(layers)
table.sort(layers)
table.insert(parts, "layers=" .. table.concat(layers, "|"))
parts[#parts + 1] = "layers=" .. table.concat(layers, "|")
end
end


table.sort(parts)
table.sort(parts)
return table.concat(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)
return normalizeSpritePath(entry.sprite)
end
local function getPrefix(id, project)
if project ~= "" and JsonPaths.has(id, project) then
return project .. ":"
end
return ""
end
end


Строка 100: Строка 138:
local item = mw.text.trim(part)
local item = mw.text.trim(part)
if item ~= "" then
if item ~= "" then
table.insert(result, item)
result[#result + 1] = item
end
end
end
end
Строка 154: Строка 192:
local parents = getParents(entry)
local parents = getParents(entry)


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


Строка 179: Строка 215:


return result
return result
end
local function getFirstSpriteAndState(entry)
local spritePath = getSpritePath(entry)
local states = getSpriteStates(entry)
if not spritePath then
return nil, nil
end
if states and #states > 0 and states[1].state then
return spritePath, states[1].state
end
if entry and entry.state then
return spritePath, tostring(entry.state)
end
return spritePath, nil
end
local function buildSpriteValue(entry)
local spritePath, stateName = getFirstSpriteAndState(entry)
if not spritePath then
return nil
end
if stateName and stateName ~= "" then
return spritePath .. " (" .. stateName .. ")"
end
return spritePath
end
local function getFirstSpriteAndState(entry)
local spritePath = getSpritePath(entry)
local states = getSpriteStates(entry)
if not spritePath then
return nil, nil
end
if states and #states > 0 and states[1].state then
return spritePath, states[1].state
end
if entry and entry.state then
return spritePath, tostring(entry.state)
end
return spritePath, nil
end
local function buildLinkedSpriteValue(entry, baseUrl)
local spritePath, stateName = getFirstSpriteAndState(entry)
if not spritePath then
return nil
end
local pathLink = "[" .. baseUrl .. spritePath .. " " .. spritePath .. "]"
if stateName and stateName ~= "" then
local stateLink = "[" .. baseUrl .. spritePath .. "/" .. stateName .. ".png " .. stateName .. "]"
return pathLink .. " (" .. stateLink .. ")"
end
return pathLink
end
end


Строка 257: Строка 224:


spriteGroups[key] = spriteGroups[key] or {}
spriteGroups[key] = spriteGroups[key] or {}
table.insert(spriteGroups[key], { id = id, entry = entry })
spriteGroups[key][#spriteGroups[key] + 1] = { id = id, entry = entry }
end
end


Строка 268: Строка 235:
for _, obj in ipairs(group) do
for _, obj in ipairs(group) do
local id = obj.id
local id = obj.id
local prefix = getPrefix(id, project)
local prefix = (project ~= "" and JsonPaths.has(id, project)) and (project .. ":") or ""
 
idLinks[#idLinks + 1] = "[[:Файл:" .. prefix .. id .. ".png]]"
table.insert(idLinks, "[[:Файл:" .. prefix .. id .. ".png]]")
end
end


local firstId = group[1].id
local firstId = group[1].id
local firstEntry = group[1].entry
local firstEntry = group[1].entry
local prefix = getPrefix(firstId, project)
local prefix = (project ~= "" and JsonPaths.has(firstId, project)) and (project .. ":") or ""
local spriteValue = buildLinkedSpriteValue(firstEntry, baseUrl) or ""
 
local spritePath = getSpritePath(firstEntry)
local spriteValue = ""
 
if spritePath then
spriteValue = buildSpriteLink(baseUrl, spritePath)


table.insert(result, mw.getCurrentFrame():preprocess(
local stateName = getPrimaryState(firstEntry)
"{{Entity Sprite/Repeat|спрайты=" .. table.concat(idLinks, " ") ..
if stateName and stateName ~= "" then
spriteValue = spriteValue .. " (" .. buildStateLink(baseUrl, spritePath, stateName) .. ")"
end
end
 
result[#result + 1] = renderTemplate(
"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
"|перенаправление=" .. prefix .. firstId ..
"|перенаправление=" .. prefix .. firstId ..
"|id=" .. firstId ..
"|id=" .. firstId ..
"|спрайт=" .. spriteValue ..
"|спрайт=" .. spriteValue ..
"}}"
"}}"
))
)
end
end
end
end
Строка 297: Строка 274:
end
end


local prefix = getPrefix(id, project)
local prefix = (project ~= "" and JsonPaths.has(id, project)) and (project .. ":") or ""


local states = getSpriteStates(entry)
local stateLinks = buildStateLinks(entry, baseUrl)
local stateStr = ""
local stateStr = stateLinks and table.concat(stateLinks, ", ") or ""


if states then
return renderTemplate(
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 ..
"{{Entity Sprite/Image|файл=" .. prefix .. id ..
"|id=" .. id ..
"|id=" .. id ..
Строка 350: Строка 316:
if action == "repeat" then
if action == "repeat" then
return generateRepeatTemplate(filteredData, project, baseUrl)
return generateRepeatTemplate(filteredData, project, baseUrl)
elseif action == "image" then
elseif action == "image" then
local result = {}
local result = {}
Строка 357: Строка 322:
local t = generateTemplate(id, entry, baseUrl, project)
local t = generateTemplate(id, entry, baseUrl, project)
if t then
if t then
table.insert(result, t)
result[#result + 1] = t
end
end
end
end

Версия от 21:05, 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 getSpritePath(entry)
	return entry and normalizeSpritePath(entry.sprite) or nil
end

local function getSpriteStates(entry)
	local result = {}

	if entry and entry.layers and type(entry.layers) == "table" then
		for _, layer in ipairs(entry.layers) do
			if layer.visible ~= false and layer.state then
				result[#result + 1] = {
					state = tostring(layer.state),
					sprite = normalizeSpritePath(layer.sprite or entry.sprite)
				}
			end
		end
	elseif entry and entry.state and entry.sprite then
		result[#result + 1] = {
			state = tostring(entry.state),
			sprite = normalizeSpritePath(entry.sprite)
		}
	end

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

local function getPrimaryState(entry)
	local states = getSpriteStates(entry)

	if states and states[1] and states[1].state and states[1].state ~= "" then
		return states[1].state
	end

	if entry and entry.state then
		return tostring(entry.state)
	end

	return nil
end

local function buildSpriteLink(baseUrl, spritePath)
	return "[" .. baseUrl .. spritePath .. " " .. spritePath .. "]"
end

local function buildStateLink(baseUrl, spritePath, stateName)
	return "[" .. baseUrl .. spritePath .. "/" .. stateName .. ".png " .. stateName .. "]"
end

local function buildStateLinks(entry, baseUrl)
	local spritePath = getSpritePath(entry)
	local states = getSpriteStates(entry)

	if not spritePath or not states then
		return nil
	end

	local links = {}

	for _, item in ipairs(states) do
		if item.sprite and item.state then
			links[#links + 1] = buildStateLink(baseUrl, item.sprite, item.state)
		end
	end

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

local function renderTemplate(template)
	return mw.getCurrentFrame():preprocess(template)
end

local function buildEntryKey(entry)
	local parts = {}

	local function addField(name, value)
		if value ~= nil then
			parts[#parts + 1] = name .. "=" .. tostring(value)
		end
	end

	addField("sprite", getSpritePath(entry))
	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)
			layers[#layers + 1] = table.concat(layerParts, ",")
		end

		table.sort(layers)
		parts[#parts + 1] = "layers=" .. table.concat(layers, "|")
	end

	table.sort(parts)
	return table.concat(parts, ";")
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
			result[#result + 1] = 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 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, 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, baseUrl)
	local spriteGroups = {}

	for id, entry in pairs(data) do
		local key = buildEntryKey(entry)

		spriteGroups[key] = spriteGroups[key] or {}
		spriteGroups[key][#spriteGroups[key] + 1] = { 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 = (project ~= "" and JsonPaths.has(id, project)) and (project .. ":") or ""
				idLinks[#idLinks + 1] = "[[:Файл:" .. prefix .. id .. ".png]]"
			end

			local firstId = group[1].id
			local firstEntry = group[1].entry
			local prefix = (project ~= "" and JsonPaths.has(firstId, project)) and (project .. ":") or ""

			local spritePath = getSpritePath(firstEntry)
			local spriteValue = ""

			if spritePath then
				spriteValue = buildSpriteLink(baseUrl, spritePath)

				local stateName = getPrimaryState(firstEntry)
				if stateName and stateName ~= "" then
					spriteValue = spriteValue .. " (" .. buildStateLink(baseUrl, spritePath, stateName) .. ")"
				end
			end

			result[#result + 1] = renderTemplate(
				"{{Entity Sprite/Repeat|файлы=" .. table.concat(idLinks, " ") ..
				"|перенаправление=" .. prefix .. 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 prefix = (project ~= "" and JsonPaths.has(id, project)) and (project .. ":") or ""

	local stateLinks = buildStateLinks(entry, baseUrl)
	local stateStr = stateLinks and table.concat(stateLinks, ", ") or ""

	return renderTemplate(
		"{{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, baseUrl)
	elseif action == "image" then
		local result = {}

		for id, entry in pairs(filteredData) do
			local t = generateTemplate(id, entry, baseUrl, project)
			if t then
				result[#result + 1] = t
			end
		end

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

	return nil
end

return p