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

Материал из МК14 | Space Station 14 Wiki
м (Фиксы фиксы)
(Отмена правки 29376, сделанной PERed (обсуждение))
Метка: отмена
 
(не показано 14 промежуточных версий 3 участников)
Строка 1: Строка 1:
local p = {}
local p = {}
 
-- Кэш для хранения данных о рецептах
-- Кэш для хранения данных о рецептах
local recipeCache = nil
local recipeCache = nil
 
-- Кэш для хранения данных о химических веществах
-- Кэш для хранения данных о химических веществах
local chemCache = nil
local chemCache = nil
 
-- Кэш для перевода идентификаторов
local translationCache = {}
-- Функция для логирования
-- Функция для логирования
local function log(message)
local function log(message)
     mw.log("DEBUG: " .. message)
     mw.log("DEBUG: " .. message)
end
end
 
-- Функция для загрузки данных о рецептах из JSON-файла
-- Функция для загрузки данных о рецептах из JSON-файла
local function loadRecipes()
local function loadRecipes()
Строка 30: Строка 33:
     end
     end
end
end
 
-- Функция для загрузки данных о химических веществах из JSON-файла
-- Функция для загрузки данных о химических веществах из JSON-файла
local function loadChemPrototypes()
local function loadChemPrototypes()
Строка 49: Строка 52:
     end
     end
end
end
 
-- Функция для перевода ID с использованием Module:Entity Lookup (для твердых веществ)
-- Функция для перевода ID с использованием Module:Entity Lookup (для твердых веществ)
local function translateID(frame, id)
local function translateID(frame, id)
    if translationCache[id] then
        return translationCache[id]
    end
   
     local translatedName = frame:callParserFunction{ name = '#invoke', args = { 'Entity_Lookup', 'getname', id } }
     local translatedName = frame:callParserFunction{ name = '#invoke', args = { 'Entity_Lookup', 'getname', id } }
     if translatedName then
     if translatedName then
         return string.format("%s [[Файл:%s.png|32px]]", translatedName, id)
         translationCache[id] = {
            name = translatedName,
            image = string.format("[[Файл:%s.png|32px]]", id)
        }
     else
     else
         return id  -- Если перевод не найден, возвращаем исходный ID
         translationCache[id] = {
            name = id, -- Если перевод не найден, возвращаем исходный ID
            image = ""
        }
     end
     end
   
    return translationCache[id]
end
end
 
-- Функция для перевода реагента (жидкого вещества) из chem_prototypes.json
-- Функция для перевода реагента (жидкого вещества) из chem_prototypes.json
local function translateReagent(reagentId)
local function translateReagent(reagentId)
Строка 68: Строка 83:
         return reagentId  -- Если перевод не найден, возвращаем исходный ID
         return reagentId  -- Если перевод не найден, возвращаем исходный ID
     end
     end
end
-- Функция для создания хэш-таблицы с результатами рецептов
local function createRecipeResultLookup(recipes)
    local lookup = {}
    for recipeType, recipeList in pairs(recipes) do
        for recipeId, recipe in pairs(recipeList) do
            if recipe.result then
                lookup[recipe.result] = true
            end
        end
    end
    return lookup
end
-- Функция для создания ссылки на строку таблицы
local function createLinkToRow(ingredientId, ingredientName)
    return string.format("[[#%s|%s]]", ingredientId, ingredientName)
end
end


-- Функция для сортировки рецептов
-- Форматирование температуры для отображения
local function sortRecipes(sortedRecipes, recipeType, frame)
local function formatTemperature(recipe)
     if recipeType == "grindableRecipes" then
     local tempString = ""
        table.sort(sortedRecipes, function(a, b)
   
            local aName = translateID(frame, a.data.input or "")
    -- Проверяем наличие минимальной температуры
            local bName = translateID(frame, b.data.input or "")
    local hasMin = recipe.minTemp and recipe.minTemp ~= 0
            return aName < bName
    -- Проверяем наличие максимальной температуры (если есть поле maxTemp)
         end)
    local hasMax = recipe.maxTemp and recipe.maxTemp ~= 0
   
    if hasMin and hasMax then
        tempString = string.format("от %sК до %sК", recipe.minTemp, recipe.maxTemp)
    elseif hasMin then
        tempString = string.format("выше %sК", recipe.minTemp)
    elseif hasMax then
         tempString = string.format("ниже %sК", recipe.maxTemp)
     else
     else
         table.sort(sortedRecipes, function(a, b)
         tempString = "Нет данных"
            local aName = translateID(frame, a.data.result or "")
            local bName = translateID(frame, b.data.result or "")
            return aName < bName
        end)
     end
     end
   
    return tempString
end
end
 
-- Основная функция для генерации таблицы с рецептами
-- Основная функция для генерации таблицы с рецептами
p.fillRecipeTable = function(frame)
p.fillRecipeTable = function(frame)
Строка 92: Строка 130:
     local recipeType = args.recipeType or "microwaveRecipes"
     local recipeType = args.recipeType or "microwaveRecipes"
     local templateName = args.template or "RecipeRow"
     local templateName = args.template or "RecipeRow"
 
     local out = ""
     local out = ""
      
      
Строка 102: Строка 140:
     end
     end
      
      
     -- Создаем таблицу для сортировки
     -- Создаем хэш-таблицу для быстрой проверки результатов рецептов
     local sortedRecipes = {}
     local recipeResultLookup = createRecipeResultLookup(recipes)
   
    -- Перебираем рецепты без сортировки
     for recipeId, recipe in pairs(recipes[recipeType]) do
     for recipeId, recipe in pairs(recipes[recipeType]) do
         table.insert(sortedRecipes, { id = recipeId, data = recipe })
         local templateArgs = {}
    end
 
        -- Определяем resultId для якоря
    -- Сортировка рецептов
        local resultId = recipe.result or recipeId  -- Используем result, если он есть, иначе recipeId
    sortRecipes(sortedRecipes, recipeType, frame)
 
        -- Добавляем id в аргументы шаблона (кроме grindableRecipes)
    -- Перебираем отсортированные рецепты
         if recipeType ~= "grindableRecipes" then
    local count = 0
             templateArgs.id = resultId
    for _, recipeData in ipairs(sortedRecipes) do
         count = count + 1
        if count > 10 then -- Ограничим количество рецептов для тестирования
             break
         end
         end
 
        local recipe = recipeData.data
        local templateArgs = {}
 
         -- Обработка для microwaveRecipes
         -- Обработка для microwaveRecipes
         if recipeType == "microwaveRecipes" then
         if recipeType == "microwaveRecipes" then
             -- Переводим результат
             -- Переводим результат
             local result = translateID(frame, recipe.result) or "Нет результата"
             local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
              
              
             -- Формируем список ингредиентов (solids)
             -- Формируем список ингредиентов (solids)
Строка 131: Строка 166:
             if recipe.solids and type(recipe.solids) == "table" then
             if recipe.solids and type(recipe.solids) == "table" then
                 for solidId, amount in pairs(recipe.solids) do
                 for solidId, amount in pairs(recipe.solids) do
                     local ingredientName = translateID(frame, solidId)
                     local solidData = translateID(frame, solidId)
                     table.insert(solidsList, string.format("%s (%d)", ingredientName, amount))
                    local ingredientName = solidData.name
                    local ingredientImage = solidData.image
                    -- Проверяем, можно ли приготовить ингредиент
                    if recipeResultLookup[solidId] then
                        ingredientName = createLinkToRow(solidId, ingredientName)
                    end
                     table.insert(solidsList, string.format("%s %s (%d)", ingredientName, ingredientImage, amount))
                 end
                 end
             end
             end
Строка 146: Строка 187:
              
              
             -- Формируем аргументы для шаблона
             -- Формируем аргументы для шаблона
             templateArgs = {
             templateArgs.result = result .. " " .. resultImage
                result = result,
            templateArgs.solids = table.concat(solidsList, "</br>") or "Нет ингредиентов"
                solids = table.concat(solidsList, ", ") or "Нет ингредиентов",
            templateArgs.reagents = table.concat(reagentsList, "</br>") or "Нет реагентов"
                reagents = table.concat(reagentsList, ", ") or "Нет реагентов",
            templateArgs.time = recipe.time or "Нет данных"
                time = recipe.time or "Нет данных"
            }
 
         -- Обработка для sliceableRecipes
         -- Обработка для sliceableRecipes
         elseif recipeType == "sliceableRecipes" then
         elseif recipeType == "sliceableRecipes" then
             local input = recipe.input and translateID(frame, recipe.input) or "Нет входного элемента"
             local inputData = translateID(frame, recipe.input)
             local result = recipe.result and translateID(frame, recipe.result) or "Нет результата"
            local input = inputData.name or "Нет входного элемента"
             local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
             local count = recipe.count or "Нет данных"
             local count = recipe.count or "Нет данных"
 
             templateArgs = {
             templateArgs.input = input .. " " .. inputImage
                input = input,
            templateArgs.result = result .. " " .. resultImage
                result = result,
            templateArgs.count = count
                count = count
            }
 
         -- Обработка для grindableRecipes
         -- Обработка для grindableRecipes
         elseif recipeType == "grindableRecipes" then
         elseif recipeType == "grindableRecipes" then
             local input = recipe.input and translateID(frame, recipe.input) or "Нет входного элемента"
             local inputData = translateID(frame, recipe.input)
            local input = inputData.name or "Нет входного элемента"
            local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
             local resultList = {}
             local resultList = {}
 
             if recipe.result and type(recipe.result) == "table" then
             if recipe.result and type(recipe.result) == "table" then
                 for reagentId, amount in pairs(recipe.result) do
                 for reagentId, amount in pairs(recipe.result) do
Строка 176: Строка 229:
                 end
                 end
             end
             end
 
             templateArgs = {
             templateArgs.input = input .. " " .. inputImage
                input = input,
            templateArgs.result = table.concat(resultList, "</br>") or "Нет результата"
                result = table.concat(resultList, ", ") or "Нет результата"
            }
 
         -- Обработка для heatableRecipes
         -- Обработка для heatableRecipes
         elseif recipeType == "heatableRecipes" then
         elseif recipeType == "heatableRecipes" then
             local input = recipe.input and translateID(frame, recipe.input) or "Нет входного элемента"
             local inputData = translateID(frame, recipe.input)
             local result = recipe.result and translateID(frame, recipe.result) or "Нет результата"
            local input = inputData.name or "Нет входного элемента"
             local minTemp = recipe.minTemp or "Нет данных"
             local inputImage = inputData.image or ""
 
            -- Проверяем, можно ли приготовить input
             templateArgs = {
            if recipeResultLookup[recipe.input] then
                input = input,
                input = createLinkToRow(recipe.input, input)
                result = result,
            end
                minTemp = minTemp
            }
            local resultData = translateID(frame, recipe.result)
 
            local result = resultData.name or "Нет результата"
             local resultImage = resultData.image or ""
           
             local minTemp = formatTemperature(recipe)
            templateArgs.input = input .. " " .. inputImage
            templateArgs.result = result .. " " .. resultImage
            templateArgs.minTemp = minTemp  
         -- Обработка для toolmadeRecipes
         -- Обработка для toolmadeRecipes
         elseif recipeType == "toolmadeRecipes" then
         elseif recipeType == "toolmadeRecipes" then
             local input = recipe.input and translateID(frame, recipe.input) or "Нет входного элемента"
             local inputData = translateID(frame, recipe.input)
             local result = recipe.result and translateID(frame, recipe.result) or "Нет результата"
            local input = inputData.name or "Нет входного элемента"
             local tool = recipe.tool and translateID(frame, recipe.tool) or "Нет инструмента"
             local inputImage = inputData.image or ""
 
            -- Проверяем, можно ли приготовить input
             templateArgs = {
            if recipeResultLookup[recipe.input] then
                input = input,
                input = createLinkToRow(recipe.input, input)
                result = result,
            end
                tool = tool
            }
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
             local resultImage = resultData.image or ""
            local toolData = translateID(frame, recipe.tool)
            local tool = toolData.name or "Нет инструмента"
            local toolImage = toolData.image or ""
             templateArgs.input = input .. " " .. inputImage
            templateArgs.result = result .. " " .. resultImage
            templateArgs.tool = tool .. " " .. toolImage
         end
         end
 
        -- Добавляем якорь для строки таблицы
        out = out .. string.format('|- id="%s"\n', recipe.id)
 
         -- Генерация строки таблицы с использованием шаблона
         -- Генерация строки таблицы с использованием шаблона
         out = out .. frame:expandTemplate{ title = templateName, args = templateArgs } .. "\n"
         out = out .. frame:expandTemplate{ title = templateName, args = templateArgs } .. "\n"
Строка 216: Строка 282:
     return out
     return out
end
end
 
return p
return p

Текущая версия от 22:22, 1 июля 2026

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

local p = {}
 
-- Кэш для хранения данных о рецептах
local recipeCache = nil
 
-- Кэш для хранения данных о химических веществах
local chemCache = nil
 
-- Кэш для перевода идентификаторов
local translationCache = {}
 
-- Функция для логирования
local function log(message)
    mw.log("DEBUG: " .. message)
end
 
-- Функция для загрузки данных о рецептах из JSON-файла
local function loadRecipes()
    if recipeCache then
        return recipeCache
    end
    
    local success, data = pcall(function()
        return mw.text.jsonDecode(mw.title.new("User:CapybaraBot/mealrecipes_prototypes.json"):getContent())
    end)
    
    if success and type(data) == "table" then
        recipeCache = data
        return data
    else
        log("Ошибка при загрузке JSON (mealrecipes_prototypes.json): " .. tostring(data))
        return {}
    end
end
 
-- Функция для загрузки данных о химических веществах из JSON-файла
local function loadChemPrototypes()
    if chemCache then
        return chemCache
    end
    
    local success, data = pcall(function()
        return mw.text.jsonDecode(mw.title.new("User:CapybaraBot/chem_prototypes.json"):getContent())
    end)
    
    if success and type(data) == "table" then
        chemCache = data
        return data
    else
        log("Ошибка при загрузке JSON (chem_prototypes.json): " .. tostring(data))
        return {}
    end
end
 
-- Функция для перевода ID с использованием Module:Entity Lookup (для твердых веществ)
local function translateID(frame, id)
    if translationCache[id] then
        return translationCache[id]
    end
    
    local translatedName = frame:callParserFunction{ name = '#invoke', args = { 'Entity_Lookup', 'getname', id } }
    if translatedName then
        translationCache[id] = {
            name = translatedName,
            image = string.format("[[Файл:%s.png|32px]]", id)
        }
    else
        translationCache[id] = {
            name = id,  -- Если перевод не найден, возвращаем исходный ID
            image = ""
        }
    end
    
    return translationCache[id]
end
 
-- Функция для перевода реагента (жидкого вещества) из chem_prototypes.json
local function translateReagent(reagentId)
    local chemData = loadChemPrototypes()
    if chemData[reagentId] and chemData[reagentId].name then
        return chemData[reagentId].name
    else
        return reagentId  -- Если перевод не найден, возвращаем исходный ID
    end
end
 
-- Функция для создания хэш-таблицы с результатами рецептов
local function createRecipeResultLookup(recipes)
    local lookup = {}
    for recipeType, recipeList in pairs(recipes) do
        for recipeId, recipe in pairs(recipeList) do
            if recipe.result then
                lookup[recipe.result] = true
            end
        end
    end
    return lookup
end
 
-- Функция для создания ссылки на строку таблицы
local function createLinkToRow(ingredientId, ingredientName)
    return string.format("[[#%s|%s]]", ingredientId, ingredientName)
end

-- Форматирование температуры для отображения
local function formatTemperature(recipe)
    local tempString = ""
    
    -- Проверяем наличие минимальной температуры
    local hasMin = recipe.minTemp and recipe.minTemp ~= 0
    -- Проверяем наличие максимальной температуры (если есть поле maxTemp)
    local hasMax = recipe.maxTemp and recipe.maxTemp ~= 0
    
    if hasMin and hasMax then
        tempString = string.format("от %sК до %sК", recipe.minTemp, recipe.maxTemp)
    elseif hasMin then
        tempString = string.format("выше %sК", recipe.minTemp)
    elseif hasMax then
        tempString = string.format("ниже %sК", recipe.maxTemp)
    else
        tempString = "Нет данных"
    end
    
    return tempString
end
 
-- Основная функция для генерации таблицы с рецептами
p.fillRecipeTable = function(frame)
    local args = frame.args
    local recipeType = args.recipeType or "microwaveRecipes"
    local templateName = args.template or "RecipeRow"
 
    local out = ""
    
    -- Загрузка данных о рецептах
    local recipes = loadRecipes()
    
    if not recipes or not recipes[recipeType] then
        return "Ошибка: данные о рецептах не загружены или тип рецептов не найден."
    end
    
    -- Создаем хэш-таблицу для быстрой проверки результатов рецептов
    local recipeResultLookup = createRecipeResultLookup(recipes)
    
    -- Перебираем рецепты без сортировки
    for recipeId, recipe in pairs(recipes[recipeType]) do
        local templateArgs = {}
 
        -- Определяем resultId для якоря
        local resultId = recipe.result or recipeId  -- Используем result, если он есть, иначе recipeId
 
        -- Добавляем id в аргументы шаблона (кроме grindableRecipes)
        if recipeType ~= "grindableRecipes" then
            templateArgs.id = resultId
        end
 
        -- Обработка для microwaveRecipes
        if recipeType == "microwaveRecipes" then
            -- Переводим результат
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
            
            -- Формируем список ингредиентов (solids)
            local solidsList = {}
            if recipe.solids and type(recipe.solids) == "table" then
                for solidId, amount in pairs(recipe.solids) do
                    local solidData = translateID(frame, solidId)
                    local ingredientName = solidData.name
                    local ingredientImage = solidData.image
                    -- Проверяем, можно ли приготовить ингредиент
                    if recipeResultLookup[solidId] then
                        ingredientName = createLinkToRow(solidId, ingredientName)
                    end
                    table.insert(solidsList, string.format("%s %s (%d)", ingredientName, ingredientImage, amount))
                end
            end
            
            -- Формируем список реагентов (reagents)
            local reagentsList = {}
            if recipe.reagents and type(recipe.reagents) == "table" then
                for reagentId, amount in pairs(recipe.reagents) do
                    local reagentName = translateReagent(reagentId)
                    table.insert(reagentsList, string.format("%s (%d)", reagentName, amount))
                end
            end
            
            -- Формируем аргументы для шаблона
            templateArgs.result = result .. " " .. resultImage
            templateArgs.solids = table.concat(solidsList, "</br>") or "Нет ингредиентов"
            templateArgs.reagents = table.concat(reagentsList, "</br>") or "Нет реагентов"
            templateArgs.time = recipe.time or "Нет данных"
 
        -- Обработка для sliceableRecipes
        elseif recipeType == "sliceableRecipes" then
            local inputData = translateID(frame, recipe.input)
            local input = inputData.name or "Нет входного элемента"
            local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
 
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
            local count = recipe.count or "Нет данных"
 
            templateArgs.input = input .. " " .. inputImage
            templateArgs.result = result .. " " .. resultImage
            templateArgs.count = count
 
        -- Обработка для grindableRecipes
        elseif recipeType == "grindableRecipes" then
            local inputData = translateID(frame, recipe.input)
            local input = inputData.name or "Нет входного элемента"
            local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
 
            local resultList = {}
 
            if recipe.result and type(recipe.result) == "table" then
                for reagentId, amount in pairs(recipe.result) do
                    local reagentName = translateReagent(reagentId)
                    table.insert(resultList, string.format("%s (%d)", reagentName, amount))
                end
            end
 
            templateArgs.input = input .. " " .. inputImage
            templateArgs.result = table.concat(resultList, "</br>") or "Нет результата"
 
        -- Обработка для heatableRecipes
        elseif recipeType == "heatableRecipes" then
            local inputData = translateID(frame, recipe.input)
            local input = inputData.name or "Нет входного элемента"
            local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
 
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
            
            local minTemp = formatTemperature(recipe)
 
            templateArgs.input = input .. " " .. inputImage
            templateArgs.result = result .. " " .. resultImage
            templateArgs.minTemp = minTemp 
 
        -- Обработка для toolmadeRecipes
        elseif recipeType == "toolmadeRecipes" then
            local inputData = translateID(frame, recipe.input)
            local input = inputData.name or "Нет входного элемента"
            local inputImage = inputData.image or ""
            -- Проверяем, можно ли приготовить input
            if recipeResultLookup[recipe.input] then
                input = createLinkToRow(recipe.input, input)
            end
 
            local resultData = translateID(frame, recipe.result)
            local result = resultData.name or "Нет результата"
            local resultImage = resultData.image or ""
 
            local toolData = translateID(frame, recipe.tool)
            local tool = toolData.name or "Нет инструмента"
            local toolImage = toolData.image or ""
 
            templateArgs.input = input .. " " .. inputImage
            templateArgs.result = result .. " " .. resultImage
            templateArgs.tool = tool .. " " .. toolImage
        end
 
        -- Генерация строки таблицы с использованием шаблона
        out = out .. frame:expandTemplate{ title = templateName, args = templateArgs } .. "\n"
    end
    
    return out
end
 
return p