Guest User

exchanger.lua

a guest
May 12th, 2025
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.03 KB | None | 0 0
  1. --v2.2
  2. --[[
  3.     https://pastebin.com/jaYhuD0k - serafim7 version
  4.     https://pastebin.com/JXdK09U7 - Rijen version
  5.  
  6.     https://i.imgur.com/UCfMoT7.png - обустройство
  7.     Адаптер подключен к интерфесу на котором стоит PIM. В адаптере стоит настроенный МФУ для общения с самим PIM'ом
  8.  
  9.     https://i.imgur.com/0YMfy7h.png - порядок выставления руд в инвентаре для автоматической настройки
  10.     https://i.imgur.com/QuqiGbi.png - результат
  11.     https://youtu.be/YoQVaSJRicc
  12. ]]
  13. --
  14.  
  15. local unicode = require("unicode")
  16. local computer = require("computer")
  17. local com = require("component")
  18. local event = require("event")
  19. local fs = require("filesystem")
  20. local shell = require("shell")
  21. local inspect = {}
  22. if not fs.exists("/lib/inspect.lua") then
  23.     shell.execute("wget -q https://raw.githubusercontent.com/kikito/inspect.lua/master/inspect.lua /lib/inspect.lua")
  24. end
  25. inspect = require("inspect")
  26.  
  27. local me = com.isAvailable("me_interface") and com.me_interface or error("Интерфейс не подключен")
  28. local pim = com.isAvailable("pim") and com.pim or error("PIM не подключен")
  29. local gpu = com.gpu
  30.  
  31. local w, h = 80, 50
  32. local defBG, defFG = gpu.getBackground(), gpu.getForeground()
  33. gpu.setResolution(w, h)
  34.  
  35. local ore_list = {
  36.     {
  37.         take = { label = "Алмазная руда", name = "minecraft:diamond_ore", damage = 0.0, amount = 1 },
  38.         give = { label = "Алмаз", name = "minecraft:diamond", damage = 0.0, amount = 2 }
  39.     },
  40.     {
  41.         take = { label = "Железная руда", name = "minecraft:iron_ore", damage = 0.0, amount = 9 },
  42.         give = { label = "Железный слиток", name = "minecraft:iron_ingot", damage = 0.0, amount = 22 }
  43.     },
  44.     {
  45.         take = { label = "Золотая руда", name = "minecraft:gold_ore", damage = 0.0, amount = 9 },
  46.         give = { label = "Золотой слиток", name = "minecraft:gold_ingot", damage = 0.0, amount = 22 }
  47.     },
  48.     {
  49.         take = { label = "Лазуритовая руда", name = "minecraft:lapis_ore", damage = 0.0, amount = 1 },
  50.         give = { label = "Лазурит", name = "minecraft:dye", damage = 4.0, amount = 12 }
  51.     },
  52.     {
  53.         take = { label = "Красная руда", name = "minecraft:redstone_ore", damage = 0.0, amount = 1 },
  54.         give = { label = "Блок красного камня", name = "minecraft:redstone_block", damage = 0.0, amount = 1 }
  55.     },
  56.     {
  57.         take = { label = "Угольная руда", name = "minecraft:coal_ore", damage = 0.0, amount = 1 },
  58.         give = { label = "Уголь", name = "minecraft:coal", damage = 0.0, amount = 3 }
  59.     },
  60.     {
  61.         take = { label = "Руда истинного кварца", name = "appliedenergistics2:tile.OreQuartz", damage = 0.0, amount = 1 },
  62.         give = { label = "Кристалл ист. кварца", name = "appliedenergistics2:item.ItemMultiMaterial", damage = 0.0, amount = 3 }
  63.     },
  64.     {
  65.         take = { label = "Заряж. руда ист. квар", name = "appliedenergistics2:tile.OreQuartzCharged", damage = 0.0, amount = 1 },
  66.         give = { label = "Заряж. крист. кварца", name = "appliedenergistics2:item.ItemMultiMaterial", damage = 1.0, amount = 3 }
  67.     },
  68.     {
  69.         take = { label = "Кварцевая руда", name = "minecraft:quartz_ore", damage = 0.0, amount = 1 },
  70.         give = { label = "Кварц", name = "minecraft:quartz", damage = 0.0, amount = 4 }
  71.     },
  72.     {
  73.         take = { label = "Медная руда", name = "IC2:blockOreCopper", damage = 0.0, amount = 9 },
  74.         give = { label = "Медный слиток", name = "IC2:itemIngot", damage = 0.0, amount = 22 }
  75.     },
  76.     {
  77.         take = { label = "Оловянная руда", name = "IC2:blockOreTin", damage = 0.0, amount = 9 },
  78.         give = { label = "Оловянный слиток", name = "IC2:itemIngot", damage = 1.0, amount = 22 }
  79.     },
  80.     {
  81.         take = { label = "Серебряная руда", name = "ThermalFoundation:Ore", damage = 2.0, amount = 7 },
  82.         give = { label = "Серебрянный слиток", name = "IC2:itemIngot", damage = 6.0, amount = 22 }
  83.     },
  84.     {
  85.         take = { label = "Платиновая руда", name = "ThermalFoundation:Ore", damage = 5.0, amount = 1 },
  86.         give = { label = "Измельчённая платина", name = "ThermalFoundation:material", damage = 37.0, amount = 2 }
  87.     },
  88.     {
  89.         take = { label = "Никелевая руда", name = "ThermalFoundation:Ore", damage = 4.0, amount = 1 },
  90.         give = { label = "Измельчённый никель", name = "ThermalFoundation:material", damage = 36.0, amount = 2 }
  91.     },
  92.     {
  93.         take = { label = "Дракониевая руда", name = "DraconicEvolution:draconiumOre", damage = 0.0, amount = 1 },
  94.         give = { label = "Дракониевая пыль", name = "DraconicEvolution:draconiumDust", damage = 0.0, amount = 2 }
  95.     }
  96. }
  97. local currDir = shell.getWorkingDirectory()
  98. local oresPath = currDir .. "/exchanger_ores.txt"
  99.  
  100. if fs.exists(oresPath) then
  101.     local file = io.open(oresPath, "r")
  102.     ore_list = file:read("*all")
  103.     file:close()
  104.     local success, ore_table = pcall(load("return " .. ore_list))
  105.     if not success then
  106.         return error(string.format(
  107.             "Ошибка в таблице %s\nНеобходимо исправить или создать заново, удалив текущую\nУдалить - rm exchanger_ores.txt",
  108.             oresPath))
  109.     end
  110.     ore_list = ore_table
  111. end
  112.  
  113. local function saveOres(ores)
  114.     io.open(oresPath, "w"):write(inspect(ores)):close()
  115. end
  116.  
  117. local function center(height, text, color)
  118.     gpu.fill(1, height, w, 1, " ")
  119.     gpu.setForeground(color)
  120.     gpu.set(math.floor(w / 2 - unicode.len(text) / 2), height, text)
  121. end
  122.  
  123. local function formatNumber(num)
  124.     local symbols = { "", "K", "M", "B", "T" }
  125.     local formattedNum = num
  126.     local symbolIndex = 1
  127.  
  128.     while formattedNum >= 1000 do
  129.         formattedNum = formattedNum / 1000
  130.         symbolIndex = symbolIndex + 1
  131.     end
  132.  
  133.     formattedNum = string.format("%.1f", formattedNum)
  134.  
  135.     if formattedNum:sub(-2) == ".0" then
  136.         formattedNum = formattedNum:sub(1, -3)
  137.     end
  138.  
  139.     return formattedNum .. symbols[symbolIndex]
  140. end
  141.  
  142. local function updIngotsSize()
  143.     if #ore_list < 1 then return false end
  144.     local totalOre = 0
  145.  
  146.     for _, ore in ipairs(ore_list) do
  147.         local success, item = pcall(function()
  148.             return me.getItemDetail({ id = ore.give.name, dmg = ore.give.damage }).basic()
  149.         end)
  150.  
  151.         if success and item ~= nil then
  152.             ore.size = item.qty
  153.             totalOre = totalOre + item.qty
  154.             ore.maxSize = item.max_size
  155.         else
  156.             ore.size = 0
  157.             ore.maxSize = 1
  158.         end
  159.     end
  160.  
  161.     if totalOre == 0 then
  162.         return false
  163.     end
  164.  
  165.     return true
  166. end
  167.  
  168. local function drawInfo(type)
  169.     local line = 2
  170.  
  171.     if type == "full" then
  172.         gpu.fill(1, 1, w, h - 16, " ")
  173.     end
  174.  
  175.     for i, ore in pairs(ore_list) do
  176.         local print_row = line + i
  177.  
  178.         if type == "full" then
  179.             gpu.setForeground(0xFF00FF)
  180.             local takeAmount = formatNumber(ore.take.amount)
  181.             gpu.set(29 - #takeAmount, print_row, takeAmount)
  182.             gpu.set(33, print_row, formatNumber(ore.give.amount))
  183.  
  184.             gpu.setForeground(0x00ff00)
  185.             gpu.set(5, print_row, ore.take.label)
  186.             gpu.set(42, print_row, ore.give.label)
  187.  
  188.             gpu.setForeground(0xFFFF00)
  189.             gpu.set(30, print_row, unicode.char(0xFF1E))
  190.             gpu.set(63, print_row, "Доступно:")
  191.             gpu.setForeground(0x202020)
  192.             gpu.set(2, print_row + 1, string.rep("═", w - 2))
  193.         end
  194.  
  195.         if type == "full" or type == "ingots" then
  196.             gpu.fill(73, print_row, w - 73, 1, " ")
  197.             gpu.setForeground(0xFF00FF)
  198.             gpu.set(73, print_row, formatNumber(ore.size or 0))
  199.         end
  200.  
  201.         line = line + 1
  202.     end
  203. end
  204.  
  205. local function updInfo(type)
  206.     type = type or "full"
  207.     local check = updIngotsSize()
  208.  
  209.     if not check then
  210.         center(h - 15, "Нет соединения с МЭ или руды не настроены", 0xff0000)
  211.     end
  212.     drawInfo(type)
  213.  
  214.     return check
  215. end
  216.  
  217.  
  218. local function giveIngot(toGive, ore, index)
  219.     local totalGive = 0
  220.     while totalGive < toGive do
  221.         local giveSize = math.min(toGive - totalGive, ore.maxSize)
  222.         local success, res = pcall(me.exportItem, { id = ore.give.name, dmg = ore.give.damage }, "UP", giveSize)
  223.  
  224.         if success and res.size > 0 then
  225.             totalGive = totalGive + res.size
  226.             ore_list[index].size = ore_list[index].size - giveSize
  227.         else
  228.             center(h - 15, "Oсвободите место в инвентаре", 0xff0000)
  229.             center(h - 14, string.format("Ожидаю выдать %d %s", toGive - totalGive, ore.give.label), 0xFFFFFF)
  230.             os.sleep(1)
  231.         end
  232.     end
  233. end
  234.  
  235.  
  236. local function exchangeOre(slot, ore, index)
  237.     local curSlot = pim.getStackInSlot(slot)
  238.     if curSlot == nil then
  239.         center(h - 14, "Вы сошли с PIM, обмен прерван. (Не удалось прочесть слот)", 0xff0000)
  240.         os.sleep(1)
  241.         gpu.fill(1, h - 14, w, 1, " ")
  242.         return false
  243.     end
  244.  
  245.     local userOreSize = curSlot.qty
  246.     local takeSize = userOreSize - math.fmod(userOreSize, ore.take.amount)
  247.     if takeSize == 0 or userOreSize < takeSize then
  248.         return true
  249.     end
  250.     local giveSize = userOreSize * ore.give.amount
  251.  
  252.     if ore.size < giveSize then
  253.         center(h - 14, string.format("%s недостаточно для обмена", ore.give.label), 0xff0000)
  254.         os.sleep(2)
  255.         gpu.fill(1, h - 14, w, 1, " ")
  256.         return false
  257.     end
  258.  
  259.     local takedOre = pim.pushItem("DOWN", slot, takeSize)
  260.  
  261.     if takedOre == nil then
  262.         center(h - 14, "Вы сошли с PIM, обмен прерван. (Не удалось извлечь руду)", 0xff0000)
  263.         os.sleep(1)
  264.         return false
  265.     elseif takedOre == 0 then
  266.         center(h - 14, "В выбраном слоте руды нет.. А была.. Хмм...", 0x505050)
  267.         os.sleep(1)
  268.     else
  269.         giveSize = math.floor(takedOre / ore.take.amount) * ore.give.amount
  270.         center(h - 14, string.format("Меняю %d %s на %d %s", takedOre, ore.take.label, giveSize, ore.give.label),
  271.             0xffffff)
  272.         giveIngot(giveSize, ore, index)
  273.     end
  274.     gpu.fill(1, h - 14, w, 1, " ")
  275.     return true
  276. end
  277.  
  278. local function checkInventory()
  279.     local wait = 2
  280.     for i = wait, 1, -1 do
  281.         center(h - 14, string.format("Обмен через %d сек...", i), 0x505050)
  282.         os.sleep(1)
  283.     end
  284.     local size = pim.getInventorySize()
  285.     local data = pim.getAllStacks(0)
  286.     local forceBreak = false
  287.  
  288.     for slot = 1, size do
  289.         if forceBreak then
  290.             break
  291.         elseif data[slot] then
  292.             for index, ore in pairs(ore_list) do
  293.                 if data[slot].id == ore.take.name and data[slot].dmg == ore.take.damage then
  294.                     local check = exchangeOre(slot, ore, index)
  295.                     if not check then
  296.                         forceBreak = true
  297.                         break
  298.                     end
  299.                 end
  300.             end
  301.         end
  302.     end
  303.  
  304.     drawInfo("ingots")
  305.  
  306.     if pim.getInventoryName() ~= "pim" then
  307.         center(h - 15, "Обмен окончен! Приходите ещё!", 0xffffff)
  308.         return checkInventory()
  309.     else
  310.         event.push("player_off")
  311.     end
  312. end
  313.  
  314. local function isAdmin(user)
  315.     local adminUsers = table.pack(computer.users())
  316.     local check = false
  317.     for _, adminUser in pairs(adminUsers) do
  318.         if adminUser == user then
  319.             check = true
  320.             break
  321.         end
  322.     end
  323.     return check
  324. end
  325.  
  326. local function handleEvent(eventName, ...)
  327.     local args = { ... }
  328.     if eventName == "interrupted" then
  329.         gpu.setBackground(defBG)
  330.         gpu.setForeground(defFG)
  331.         gpu.fill(1, 1, w, h, " ")
  332.         os.exit()
  333.         return true
  334.     elseif eventName == "player_on" then
  335.         local check = updInfo("ingots")
  336.         if not check then
  337.             return
  338.         end
  339.         center(h - 15, string.format("Приветствую, %s! Начинаю обмен", args[1]), 0xffffff)
  340.         checkInventory()
  341.     elseif eventName == "player_off" then
  342.         local check = updInfo("ingots")
  343.         if not check then
  344.             return
  345.         end
  346.         center(h - 15, "Для обмена встаньте на PIM и не сходите до окончания обмена", 0xffffff)
  347.         center(h - 14, "Обновлю доступные руды и связь с МЭ как только наступите", 0x505050)
  348.     elseif eventName == "touch" then
  349.         if args[2] >= w - 38 and args[3] >= h - 1 then
  350.             local admin = isAdmin(args[5])
  351.             if not admin then
  352.                 return
  353.             end
  354.  
  355.             computer.beep(1500, 0.1)
  356.             local wait = 5
  357.             for i = wait, 1, -1 do
  358.                 center(h - 14, string.format("Начну сканировать инвентарь через %d сек...", i), 0x505050)
  359.                 os.sleep(1)
  360.             end
  361.  
  362.             center(h - 14, "Сканирую...", 0xffffff)
  363.             computer.beep(1500, 0.8)
  364.             if pim.getInventoryName() ~= "pim" then
  365.                 ore_list = {}
  366.                 local data = pim.getAllStacks(0)
  367.                 local i = 10
  368.                 while i ~= 9 do
  369.                     if i == 18 or i == 27 then
  370.                         i = i + 1
  371.                     elseif i == 36 then
  372.                         i = 1
  373.                     end
  374.                     if data[i] and data[i + 1] then
  375.                         table.insert(ore_list, {
  376.                             take = { label = data[i].display_name, name = data[i].id, damage = data[i].dmg, amount = math.floor(data[i].qty) },
  377.                             give = { label = data[i + 1].display_name, name = data[i + 1].id, damage = data[i + 1].dmg, amount = math.floor(data[i + 1].qty) }
  378.                         })
  379.                     end
  380.                     i = i + 2
  381.                 end
  382.                 saveOres(ore_list)
  383.                 center(h - 14, "Обмен записан!", 0x00ff00)
  384.                 computer.beep(500, 0.2)
  385.                 updInfo()
  386.             else
  387.                 center(h - 14, "Не увидел инвентарь!", 0xff0000)
  388.                 computer.beep(2000, 0.2)
  389.                 computer.beep(2000, 0.2)
  390.             end
  391.             os.sleep(1)
  392.  
  393.             local wait = 9
  394.             for i = wait, 1, -1 do
  395.                 center(h - 14, string.format("Заработаю через %d сек...", i), 0x505050)
  396.                 os.sleep(1)
  397.             end
  398.             center(h - 14, "Обновлю доступные руды и связь с МЭ как только наступите", 0x505050)
  399.         end
  400.     end
  401. end
  402.  
  403. local function drawDescription(x, y, fore, back)
  404.     local img = [[
  405. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  406. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡐⢆⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  407. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠠⡐⣄⢢⡐⢄⢢⡐⣄⠂⡄⠀⠀⢄⢢⢰⣀⢦⡐⣄⢢⡐⠄⣂⠆⠀⠀⢀⡐⢦⠹⠌⠀⢀⡰⢠⠀⠐⣠⠀⠀⠀⠀⠀⠀⠀⠀⠄⡐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  408. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢡⠂⡄⠀⠀⠀⠀⠌⡤⠃⠀⢳⡌⠃⠘⠈⠂⠑⠈⠑⠀⠀⡜⡢⠍⠂⠑⠈⠑⠈⠃⠀⠐⣌⠎⢀⡐⠦⣜⠂⠁⠀⠀⠀⡜⡡⠂⠘⠤⡁⠀⠀⠀⠀⠀⠀⠀⢂⠱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  409. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢢⠑⡌⢢⠀⠤⣉⡜⣰⠁⠀⡣⢝⠀⠀⠀⠀⠀⠀⠀⠀⢀⠳⣹⢌⡱⢢⡱⢌⢲⢰⡀⠀⢎⠺⣤⣙⠳⣀⠀⠀⠀⠀⠠⣙⠦⠁⢨⣑⠂⠀⠀⠀⠀⠀⠀⠀⢌⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  410. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢢⡑⠈⠒⡭⠒⠌⠸⣡⠃⠀⣙⠮⡄⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠈⠁⠁⠉⣈⠞⡢⠄⠈⢎⡳⠂⠉⠳⢆⡆⣀⠀⠀⠐⡌⠦⠁⠠⣃⠎⠀⠀⠀⠀⠀⠀⠀⠌⢒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  411. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠒⡄⠁⠀⠀⠁⠀⠰⣡⠂⠀⠈⠸⣑⢋⢆⢳⡘⣔⠣⢆⢠⠱⣊⡕⣎⢖⡱⢎⠞⠁⠀⠈⣎⠱⠀⠀⠀⠈⠲⣡⠢⠄⠀⡜⡡⠂⠐⡥⢊⡴⢡⠎⡤⢁⠆⠀⠘⡀⠎⡐⢂⠰⠀⠆⡀⠀⠀⠀⠀⠀
  412. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⢌⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  413. ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  414.     ]]
  415.     fore = fore or 0xffffff
  416.     back = back or 0x0
  417.     gpu.setForeground(fore)
  418.     local i = 0
  419.     for line in img:gmatch("([^\n]*)\n?") do
  420.         gpu.set(x, y + i, line)
  421.         i = i + 1
  422.     end
  423. end
  424.  
  425. local function main()
  426.     gpu.fill(1, 1, w, h, " ")
  427.     local check = updInfo()
  428.     if check then
  429.         center(h - 15, "Для обмена встаньте на PIM и не сходите до окончания обмена", 0xffffff)
  430.     end
  431.     center(h - 14, "Обновлю доступные руды и связь с МЭ как только наступите", 0x505050)
  432.     drawDescription(1, h - 13, 0x00a400)
  433.  
  434.     while true do
  435.         handleEvent(event.pull(1))
  436.     end
  437. end
  438.  
  439. while true do
  440.     local success, err = pcall(main)
  441.     if not success then
  442.         if #err == 0 then
  443.             break
  444.         else
  445.             io.open(currDir .. "/exchanger_errors.txt", "ab"):write(err .. "\n"):close()
  446.             computer.beep(2000, 3)
  447.         end
  448.     end
  449. end
Advertisement
Add Comment
Please, Sign In to add comment