Advertisement
Altaric

Autocraft

Jan 7th, 2022 (edited)
645
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.36 KB | None | 0 0
  1. print("Autocraft v1.1")
  2.  
  3. -- Configuration
  4.  
  5. maxTasks=2     -- overridden in rules.cfg
  6. maxTaskSize=20 -- overridden in rules.cfg
  7. screenSize=40  -- overridden in rules.cfg
  8. function buildRules()
  9.     rules = {}
  10.     readConfig()
  11.     -- addRule(20  ,  "minecraft:brick" , "*" , "Brick Vanilla", 20)
  12.     -- addRule(20  ,  "nuclearcraft:alloy" , 1 , "Tough Alloy", 20)
  13.     -- addRule(20  ,  "nuclearcraft:alloy" , 2 , "Hard Carbon Alloy", 20)
  14.     -- addRule(20  ,  "nuclearcraft:alloy" , 6 , "Ferroboron Alloy", 20)
  15.     -- addRule(20  ,  "nuclearcraft:alloy" , 9 , "Lead-Plat Ingot", 20)
  16.     -- addRule(20  ,  "nuclearcraft:alloy" , 10 , "Extreme Alloy", 20)
  17.     -- addRule(20  ,  "projectred-core:resource_item", 103  , "Red Alloy Ingot", 20)
  18.     -- addRule(20  ,  "projectred-core:resource_item", 104  , "Electrotine Ingot", 20)
  19.     -- addRule(20  ,  "bloodarsenal:base_item", 4  , "Blood Iron Ingot", 20)   
  20.     -- addRule(20  ,  "thermaldynamics:servo" , 4 , "Resonant Servo", 20)
  21.     -- addRule(20  ,  "thermaldynamics:filter" , 4 , "Resonant Filter", 20)
  22.     -- addRule(100 ,  "thermaldynamics:duct_32" , 7 , "Plated Impulse Duct Opaque", 100)
  23.     -- addRule(64  ,  "immersiveengineering:stone_decoration" , 5 , "Concrete immersive", 10)
  24.     -- addRule(500  ,  "mysticalagriculture:crafting" , 1 , "Prudentium Essence", 100)
  25.     -- addRule(100  ,  "mysticalagriculture:crafting" , 2 , "Intermedium Essence", 20)
  26.     -- addRule(20   ,  "mysticalagriculture:crafting" , 3 , "Superium Essence", 5)
  27.     -- addRule(5    ,  "mysticalagriculture:crafting" , 4 , "Supremium Essence", 2)
  28.     -- addRule(20  ,  "appliedenergistics2:material" , 22 , "Logic Processor", 5)
  29.     -- addRule(5   ,  "appliedenergistics2:material" , 23 , "Calculation Processor", 5)
  30.     -- addRule(5  ,  "appliedenergistics2:material" , 24 , "Engineering Processor", 5)
  31.     -- addRule(1024,  "minecraft:glass"              , "*", "Glass", 128)
  32.     -- addRule(20  ,  "opencomputers:material"       , 3  , "Circuit Board", 100)
  33.     -- addRule(200 , "opencomputers:material"        , 4  , "PCB", 100)
  34.     -- addRule(1000 , "opencomputers:material"        , 6  , "Transistor", 200)
  35.     -- addRule(200 , "opencomputers:material"        , 7  , "Chip1", 100)
  36.     -- addRule(20  ,  "opencomputers:material"       , 8  , "Chip2", 20)
  37.     -- addRule(10  ,  "opencomputers:material"       , 9  , "Chip3", 10)
  38.     -- addRule(1024, "projectred-core:resource_item", 0  , "Circuit Plate", 300)
  39.     -- addRule(500 , "mekanism:controlcircuit"       , 0  , "Basic Control Circuit", 200)
  40.     -- addRule(100 , "mekanism:controlcircuit"       , 1  , "Adv Control Circuit", 50)
  41.     -- addRule(20  ,  "mekanism:controlcircuit"      , 2  , "Elite Control Circuit", 10)
  42.     -- addRule(2   ,   "mekanism:controlcircuit"     , 3  , "Ultim Control Circuit", 2)
  43.     -- addRulesWiggle("Plate", 10, 10)
  44.     -- addRulesWiggle("Ingot", 20, 20)
  45.     -- saveConfig()
  46. end
  47.  
  48.  
  49. -- Imports
  50.  
  51. local component = require("component")
  52. local sides = require("sides")
  53. local term = require("term")
  54. local event = require("event")
  55. local meController = component.me_controller
  56. local invController = component.inventory_controller
  57. local RSController = component.redstone
  58.  
  59. -- Utilities
  60.  
  61. function mysplit (inputstr, sep)
  62.     if inputstr == nil then return {} end
  63.     if sep == nil then
  64.             sep = "%s"
  65.     end
  66.     local t={}
  67.     for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
  68.             table.insert(t, str)
  69.     end
  70.     return t
  71. end
  72.  
  73. -- Actual code
  74.  
  75. term.clear()
  76. tasks = {}
  77.  
  78. function readChest()
  79.     print("Reading chest...")
  80.     b = false
  81.     for side= 0, 5 do
  82.         n = invController.getInventorySize(side)
  83.         print(sides[side].." : "..(n or "nil"))
  84.         if n then
  85.             for i = 1, n do
  86.                 it=invController.getStackInSlot(side, i)
  87.                 if it then print(it.name.."/"..it.damage) b = true end
  88.             end
  89.         end
  90.     end
  91.     if b then os.sleep(2) end
  92. end
  93.  
  94. function checkAvailableCPUs()
  95.     meCpus = meController.getCpus()
  96.     local occupiedCpus = 0
  97.     acpus = 0
  98.     for cpuIndex = 1, #meCpus do
  99.         -- if not meCpus[cpuIndex].busy then table.insert(acpus, meCpus[cpuIndex]) end
  100.         if not meCpus[cpuIndex].busy then acpus = acpus+1 end
  101.     end
  102.     return acpus
  103. end
  104.  
  105. function checkIfTasksEnded()
  106.     i = 1
  107.     while i <= #tasks do
  108.         t = tasks[i]
  109.         tt = t.task
  110.     -- for i, t in pairs(tasks) do
  111.         -- tt = t.task
  112.         if tt.isDone() then
  113.             table.remove(tasks, i)
  114.             print("Task finished: "..t.label)
  115.         elseif tt.isCanceled() then
  116.             table.remove(tasks, i)
  117.             print("!! Task canceled: "..t.label.." !!")
  118.         else
  119.             print("Task running: "..t.label)           
  120.             i = i + 1
  121.         end    
  122.     end
  123. end
  124.  
  125. function printStock(verbose)
  126.     l = 0
  127.     for _, rule in pairs(rules) do
  128.         if rule["dmg"] then
  129.             meItems = meController.getItemsInNetwork({ name = rule["name"], damage = rule["dmg"]})
  130.         else
  131.             meItems = meController.getItemsInNetwork({ name = rule["name"]})
  132.         end
  133.         if meItems.n == 0 then
  134.             print("Could not find "..rule["name"].."/"..(rule["dmg"] or "*"))
  135.             l = l + 1
  136.             if l > screenSize then os.sleep(2) l = 0 end
  137.             goto nextRule          
  138.         end
  139.  
  140.         if meItems.n == 1 then
  141.             if (verbose == "all") then print(rule["name"].."/"..(rule["dmg"] or "*").. " -> "..meItems[1].label.. " " .. meItems[1].size.."/"..rule["count"]) l = l + 1 if l > screenSize then os.sleep(2) l = 0 end end
  142.             if (verbose == "missing") and (meItems[1].size < rule["count"]) then print(rule["name"].."/"..(rule["dmg"] or "*").. " -> "..meItems[1].label.. " " .. meItems[1].size.."/"..rule["count"]) l = l + 1 if l > screenSize then os.sleep(2) l = 0 end end
  143.            
  144.         else
  145.             if (verbose == "all") then print(rule["name"].."/"..(rule["dmg"] or "*")) end
  146.             for i=1, meItems.n do
  147.                 it = meItems[i]
  148.                 if (verbose == "all") then print(it.label .. " " .. it.size.."/"..rule["count"]) l = l + 1 if l > screenSize then os.sleep(2) l = 0 end end
  149.                 if (verbose == "missing") and (it.size < rule["count"]) then print(it.label .. " " .. it.size.."/"..rule["count"]) l = l + 1 if l > screenSize then os.sleep(2) l = 0 end end
  150.             end
  151.         end
  152.         ::nextRule::
  153.     end
  154. end
  155.  
  156. function checkItemsAndCraft(cpus)
  157.     l = 0
  158.     for _, rule in pairs(rules) do 
  159.         if rule["count"] > 0 then -- count == 0 if disabled
  160.             if rule["dmg"] then   -- Some items don't use dmg as sub item id, mainly vanilla items
  161.                 meItems = meController.getItemsInNetwork({ name = rule["name"], damage = rule["dmg"]})
  162.             else
  163.                 meItems = meController.getItemsInNetwork({ name = rule["name"]})
  164.             end
  165.             if meItems.n == 0 then
  166.                 print("Could not find "..rule["name"].."/"..(rule["dmg"] or "*"))
  167.                 l = l + 1
  168.                 if l > screenSize then os.sleep(2) l = 0 end
  169.             else
  170.                 for i=1, meItems.n do  -- usually only 1 item found. Can be more is no "damage" is specified
  171.                     it = meItems[i]
  172.                     result = orderMissingItem(cpus, it, rule["count"], rule["limit"])
  173.                     -- if result ~= -1 then print(rule["label"].." returned "..result) end
  174.                     if (result == 3) or (result == 4) then return end -- no need to continue.
  175.                 end
  176.             end
  177.             os.sleep(0)
  178.         end
  179.     end
  180. end
  181.  
  182. -- Return values:
  183. -- Only 3 and 4 return values are used to exit the rules loop.
  184. -- -1 Nothing to do
  185. -- 0 success
  186. -- 1 already running
  187. -- 2 missing ingredients
  188. -- 3 max tasks reached
  189. -- 4 max CPUs reached
  190. -- 5 No recipe
  191.  
  192. function orderMissingItem(cpus, item, target, limit)
  193.     -- checks --
  194.     if #tasks >= maxTasks then      print("Max concurent tasks reached.")       return 3    end
  195.     if cpus <= 1 then       print("No CPU available.")      return 4    end
  196.     if item.size >= target then         return -1   end
  197.     -- Are we already crafting this ?
  198.     for _, t in pairs(tasks) do
  199.         if (t.name == item.name) and (t.dmg == item.damage) then
  200.             print("Already crafting ".. item.label)
  201.             return 1
  202.         end
  203.     end
  204.     -- print("Trying to order "..item.name.."/"..item.damage)
  205.    
  206.     -- Try to rder the craft
  207.     needed = math.min(limit, target - item.size)
  208.     craftables = meController.getCraftables({ name = item.name, damage = item.damage})
  209.     if craftables.n == 0 then       print("No recipe for ".. item.label)        return 5    end
  210.     for i=1, craftables.n do  -- supposedly the list of available recipes for this item
  211.         craftable = craftables[i]
  212.         task = craftable.request(needed)
  213.         if task.isCanceled() then
  214.             print("Missing ingredients for "..item.label.." recipe "..i)
  215.         else
  216.             print("Ordered "..needed.." "..item.label.." (recipe "..i..")")
  217.             table.insert(tasks, {name=item.name, dmg=item.damage, task=task, label=item.label})
  218.             cpus = cpus - 1
  219.             return 0
  220.         end
  221.     end
  222.     return 2
  223. end
  224.  
  225. function readConfig()
  226.     local file,err = io.open("rules.cfg", "r")
  227.     if err == nil then
  228.         version = tonumber(file:read("*line"))
  229.         if version == 2 then
  230.             maxTasks = tonumber(file:read("*line"))
  231.             maxTaskSize = tonumber(file:read("*line"))
  232.             screenSize = tonumber(file:read("*line"))
  233.             l = file:read("*line")
  234.             while l ~= 1 and l ~= nil do   
  235.                 if utf8.len(l) > 5 then
  236.                     s = mysplit(l, "\t")
  237.                     if s[3] == "*" then
  238.                         table.insert(rules, {count=tonumber(s[1]), name=s[2],                     label=s[4], limit=tonumber(s[5])})
  239.                     else
  240.                         table.insert(rules, {count=tonumber(s[1]), name=s[2], dmg=tonumber(s[3]), label=s[4], limit=tonumber(s[5])})
  241.                     end
  242.                 end
  243.                 l = file:read("*line")
  244.             end
  245.         end
  246.         if version == 3 then
  247.             maxTasks = tonumber(file:read("*line"))
  248.             maxTaskSize = tonumber(file:read("*line"))
  249.             screenSize = tonumber(file:read("*line"))          
  250.             l = file:read("*line")
  251.             while l ~= nil and l ~= 1 and l ~= 0 do
  252.                 if utf8.len(l) > 5 then
  253.                     s = mysplit(l, "+")                
  254.                     if s[3] == "*" then
  255.                         table.insert(rules, {count=tonumber(s[1]), name=s[2],                     label=s[4], limit=tonumber(s[5])})
  256.                     else
  257.                         table.insert(rules, {count=tonumber(s[1]), name=s[2], dmg=tonumber(s[3]), label=s[4], limit=tonumber(s[5])})
  258.                     end
  259.                 end
  260.                 l = file:read("*line")
  261.             end
  262.         end
  263.         file:close()
  264.     end
  265. end
  266.  
  267. function saveConfig()
  268.     os.execute("rm rules.bak")
  269.     os.execute("cp rules.cfg rules.bak")
  270.     local file,err = io.open("rules.cfg", "w")
  271.     file:write("3\n")
  272.     file:write(maxTasks.."\n")
  273.     file:write(maxTaskSize.."\n")
  274.     file:write(screenSize.."\n")
  275.     s = ""
  276.     for _, i in pairs(rules) do
  277.         -- print(i.name, i.dmg)
  278.         s = s .. (i.count.."+"..i.name.."+"..(i.dmg or "*").."+"..(i.label or "-").."+"..(i.limit or "-").."\n")
  279.     end
  280.     file:write(s)
  281.     file:close()
  282. end
  283.  
  284. function addRulesWiggle(name, qty, limit)
  285.     print("Adding wiggle rule ; this is quite long!")
  286.     craftables = meController.getCraftables()
  287.     print(craftables.n)
  288.     for i=1, craftables.n do
  289.         if ((i % 100) == 0) then print(i) end
  290.         if string.find(craftables[i].getItemStack().label, name) then
  291.             addRule(qty, craftables[i].getItemStack().name, craftables[i].getItemStack().damage, craftables[i].getItemStack().label, limit)
  292.         end
  293.     end
  294. end
  295.  
  296. function addRule(count, name, dmg, label, limit)
  297.     for _, r in pairs(rules) do
  298.         if (r.name == name ) and not r.dmg then return end
  299.         if (r.name == name ) and ((r.dmg or -1) == dmg) then return end
  300.     end
  301.     table.insert(rules, {count=count, name=name, dmg=dmg, label=label, limit=limit})
  302.     print("New rule: "..label)
  303. end
  304.  
  305. -- Main loop
  306. -- readChest()
  307. buildRules()
  308. iter=1
  309. if (RSController.getInput(sides.left) ~= 0) then print("Flip the switch to the right to activate the autocrafter.\n") end
  310. while (RSController.getInput(sides.left) == 0) do
  311.     -- term.clear()
  312.     print("Iteration "..iter.. ". Flip the switch to the right to exit.\n")
  313.     cpus = checkAvailableCPUs()
  314.     checkIfTasksEnded()
  315.     print(cpus.." CPUs available. "..#tasks.." Tasks running.\n")
  316.     -- printStock("missing")
  317.     if ((cpus > 1) and (#tasks < maxTasks))then
  318.         checkItemsAndCraft(cpus)
  319.     end
  320.     print("Yielding")
  321.     os.sleep(5)
  322.     iter = iter +1
  323. end
  324.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement