Advertisement
Skortioth

[CC]: Autocrafter w. Basalt

Aug 5th, 2022 (edited)
988
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --Basalt configurated installer
  2. local filePath = "basalt.lua" --here you can change the file path default: basalt
  3. if not(fs.exists(filePath))then
  4.     shell.run("pastebin run ESs1mg7P packed true "..filePath:gsub(".lua", "")) -- this is an alternative to the wget command
  5. end
  6. local basalt = require(filePath:gsub(".lua", "")) -- here you can change the variablename in any variablename you want default: basalt
  7.  
  8. local maxCoWorker = 3
  9.  
  10. local recipeList = {}
  11. local craftingQueue = {}
  12. local bridge = peripheral.find("rsBridge")
  13. local w, h = term.getSize()
  14.  
  15. local main = basalt.createFrame()
  16. local home = main:addFrame():setPosition(1,2):setBackground(colors.lightGray):setSize(w, h-2)
  17. local recipes = main:addFrame():setPosition(1,2):setBackground(colors.lightGray):hide()
  18. local log = main:addFrame():setPosition(1,2):setBackground(colors.lightGray):hide()
  19.  
  20. local menuBar = main:addMenubar():addItem("Home"):addItem("Recipes"):addItem("Log"):setBackground(colors.gray):setSize(w, 1):setSpace(6):setScrollable():show()
  21. menuBar:onChange(function(self)
  22.     home:hide()
  23.     recipes:hide()
  24.     log:hide()
  25.     if(self:getValue().text=="Home")then
  26.         home:show()
  27.     elseif(self:getValue().text=="Recipes")then
  28.         recipes:show()
  29.     elseif(self:getValue().text=="Log")then
  30.         log:show()
  31.     end
  32. end)
  33.  
  34. local function buttonVisuals(btn)
  35.     btn:onClick(basalt.schedule(function() btn:setBackground(colors.black) btn:setForeground(colors.lightGray) os.sleep(0.1) btn:setBackground(colors.gray) btn:setForeground(colors.black) end))
  36. end
  37.  
  38. local coworkerCount = home:addLabel():setText(maxCoWorker):setPosition(45,2):show()
  39. home:addLabel():setText("Co-Worker:"):setPosition(32,2):show()
  40. buttonVisuals(home:addButton():setText(">"):setSize(1,1):setPosition(47,2):onClick(function() if(maxCoWorker<100)then maxCoWorker = maxCoWorker+1 end coworkerCount:setText(maxCoWorker) end):show())
  41. buttonVisuals(home:addButton():setText("<"):setSize(1,1):setPosition(43,2):onClick(function() if(maxCoWorker>1)then maxCoWorker = maxCoWorker-1 end coworkerCount:setText(maxCoWorker) end):show())
  42.  
  43. local logList = log:addList():setPosition(2,2):setSize(w-2,h-3):setScrollable(false):show()
  44. local jobList = home:addList():setPosition(20,4):setSize(30,10):show()
  45. local rList = recipes:addList():setPosition(13,2):setSize(38,16):show()
  46.  
  47. local function logging(text)
  48.     logList:addItem(text)
  49.     if(logList:getItemCount()>h-3)then
  50.         logList:removeItem(1)
  51.     end
  52. end
  53.  
  54. logging("Loading autocrafter...")
  55.  
  56. function SaveToFile()
  57.     local file = io.open("recipes", "wb")
  58.     local sel = rList:getItemIndex()
  59.     rList:clear()
  60.     for _,v in pairs(recipeList)do
  61.         if(v.useDmg)then
  62.             file:write(v.name.."|"..v.damage.."|"..v.minAmount.."|"..v.maxCraftAmount.."|true|", "\n")
  63.         else
  64.             file:write(v.name.."|"..v.damage.."|"..v.minAmount.."|"..v.maxCraftAmount.."|false|", "\n")
  65.         end
  66.         rList:addItem(v.minAmount.."x "..v.name..":"..v.damage, nil, nil, v)
  67.     end
  68.     rList:selectItem(sel)
  69.     file:close()
  70. end
  71.  
  72. buttonVisuals(recipes:addButton():setPosition(2,2):setText("Remove"):setSize(8,1):onClick(function()
  73.     if(rList:getValue()~=nil)then
  74.         local sel = rList:getValue().args[1]
  75.         for k,v in pairs(recipeList)do
  76.             if(v.name==sel.name)and(tonumber(v.damage)==tonumber(sel.damage))then
  77.                 table.remove(recipeList, k)
  78.                 logging("Removed recipe: "..v.name..":"..v.damage)
  79.                 SaveToFile()
  80.             end
  81.         end
  82.     end
  83. end))
  84. local changeAmn = recipes:addInput():setPosition(4,4):setSize(5,1):setInputType("number"):setForeground(colors.black):setDefaultText("32", colors.black):onChange(function(self)
  85.     local val = tonumber(self:getValue()) or 32
  86.     if(val<0)then
  87.         self:setValue(0)
  88.     end
  89. end)
  90. buttonVisuals(recipes:addButton():setPosition(2,4):setSize(1,1):setText("-"):onClick(function()
  91.     local val = tonumber(changeAmn:getValue()) or 32
  92.     if(rList:getValue()~=nil)then
  93.         local sel = rList:getValue().args[1]
  94.         if(val>0)and(sel.name~=nil)and(sel.damage~=nil)then
  95.             for k,v in pairs(recipeList)do
  96.                 if(v.name==sel.name)and(tonumber(v.damage)==tonumber(sel.damage))then
  97.                     v.minAmount = v.minAmount - val
  98.                     if(v.minAmount < 0)then v.minAmount = 0 end
  99.                     SaveToFile()
  100.                 end
  101.             end
  102.         end
  103.     end
  104. end))
  105. buttonVisuals(recipes:addButton():setPosition(10,4):setSize(1,1):setText("+"):onClick(function()
  106.     local val = tonumber(changeAmn:getValue()) or 32
  107.     if(rList:getValue()~=nil)then
  108.         local sel = rList:getValue().args[1]
  109.         if(val>0)and(sel.name~=nil)and(sel.damage~=nil)then
  110.             for k,v in pairs(recipeList)do
  111.                 if(v.name==sel.name)and(tonumber(v.damage)==tonumber(sel.damage))then
  112.                     v.minAmount = v.minAmount + val
  113.                     SaveToFile()
  114.                 end
  115.             end
  116.         end
  117.     end
  118. end))
  119.  
  120. buttonVisuals(recipes:addButton():setPosition(2,6):setSize(8,1):setText("Set"):onClick(function()
  121.     local val = tonumber(changeAmn:getValue()) or 32
  122.     if(rList:getValue()~=nil)then
  123.         local sel = rList:getValue().args[1]
  124.         if(val>0)and(sel.name~=nil)and(sel.damage~=nil)then
  125.             for k,v in pairs(recipeList)do
  126.                 if(v.name==sel.name)and(tonumber(v.damage)==tonumber(sel.damage))then
  127.                     v.minAmount = val
  128.                     SaveToFile()
  129.                 end
  130.             end
  131.         end
  132.     end
  133. end))
  134.  
  135. local rItemFrame = home:addFrame():setPosition(7,3):setBackground(colors.gray):setSize(27,6):setMoveable(true):setBar("Remove Item", colors.black, colors.lightGray):showBar():hide()
  136. rItemFrame:addButton():setPosition(1,1):setAnchor("topRight"):setSize(1,1):setBackground(colors.black):setForeground(colors.lightGray):setText("x"):onClick(function() rItemFrame:hide() end):show()
  137. rItemFrame:addLabel():setText("Item ID:"):setPosition(2,3):show()
  138. local ritemId = rItemFrame:addInput("itemid"):setPosition(12,3):setSize(15,1):setBackground(colors.black):setForeground(colors.lightGray):setDefaultText("minecraft:stick", colors.gray):show()
  139. rItemFrame:addButton():setPosition(-7,0):setAnchor("bottomRight"):setSize(8,1):setBackground(colors.black):setForeground(colors.lightGray):setText("Remove"):onClick(function()
  140.     local id = ritemId:getValue()
  141.    
  142.     for k,v in pairs(recipeList)do
  143.         if(v.name==id)then
  144.             table.remove(recipeList, k)
  145.             logging("Removed recipe: "..v.name..":"..v.damage)
  146.         end
  147.     end
  148.     SaveToFile()
  149. end)
  150.  
  151.  
  152. local aItemFrame = home:addFrame():setPosition(7,3):setBackground(colors.gray):setSize(27,12):setMoveable(true):setBar("Add Item", colors.black, colors.lightGray):showBar():hide()
  153. aItemFrame:addLabel():setText("Item ID:"):setPosition(2,3)
  154. aItemFrame:addLabel():setText("Damage:"):setPosition(2,5)
  155. aItemFrame:addLabel():setText("Count:"):setPosition(2,7)
  156. aItemFrame:addLabel():setText("Max:"):setPosition(2,9)
  157. aItemFrame:addLabel():setText("Use Damage:"):setAnchor("bottomLeft"):setPosition(4,0)
  158. local itemId = aItemFrame:addInput():setPosition(12,3):setSize(15,1):setBackground(colors.black):setForeground(colors.lightGray):setDefaultText("minecraft:stick", colors.gray)
  159. local itemDamage = aItemFrame:addInput():setPosition(12,5):setSize(15,1):setBackground(colors.black):setForeground(colors.lightGray):setInputType("number"):setDefaultText("0", colors.gray)
  160. local itemCount = aItemFrame:addInput():setPosition(12,7):setSize(15,1):setBackground(colors.black):setForeground(colors.lightGray):setInputType("number"):setDefaultText("64", colors.gray)
  161. local itemMaxCount = aItemFrame:addInput():setPosition(12,9):setSize(15,1):setBackground(colors.black):setForeground(colors.lightGray):setInputType("number"):setDefaultText("0", colors.gray)
  162. local useDamage = aItemFrame:addCheckbox():setAnchor("bottomLeft"):setPosition(2,0):setBackground(colors.black):setForeground(colors.lightGray):setValue(true)
  163. aItemFrame:addButton():setAnchor("topRight"):setPosition(1,1):setSize(1,1):setBackground(colors.black):setForeground(colors.lightGray):setText("x"):onClick(function() aItemFrame:hide() end)
  164. aItemFrame:addButton():setAnchor("bottomRight"):setPosition(-4,0):setSize(5,1):setBackground(colors.black):setForeground(colors.lightGray):setText("Add"):onClick(function()
  165.     local id = itemId:getValue()
  166.     local dmg = itemDamage:getValue() == "" and 0 or itemDamage:getValue()
  167.     local count = itemCount:getValue() == "" and 64 or itemCount:getValue()
  168.     local maxCount = itemMaxCount:getValue() == "" and 0 or itemMaxCount:getValue()
  169.     local usedamage = useDamage:getValue() or true
  170.     if(id~="")then
  171.         local itemExist = false
  172.         for k,v in pairs(recipeList)do
  173.             if(v.name==id)then
  174.                 if(usedamage)then
  175.                     if(v.damage==dmg)then
  176.                         itemExist = true
  177.                         v.minAmount = count or 64
  178.                         v.maxCraftAmount = maxCount or 0
  179.                         logging("Edited recipe: "..(count).."x "..id..":"..dmg)
  180.                     end
  181.                 else
  182.                     itemExist = true
  183.                     v.minAmount = count or 64
  184.                     v.maxCraftAmount = maxCount or 0
  185.                     logging("Edited recipe: "..(count).."x "..id..":"..dmg)
  186.                 end
  187.             end
  188.         end
  189.  
  190.         if(itemExist == false)then
  191.             table.insert(recipeList, {name = id, damage = dmg or 0, minAmount = count, maxCraftAmount = maxCount or 0, useDmg = usedamage, fails = 0, timer = 0})
  192.             logging("Added recipe: "..(count).."x "..id..":"..dmg)
  193.         end
  194.         SaveToFile()
  195.     else
  196.         logging("Please set a ID.")
  197.     end
  198. end)
  199.  
  200. buttonVisuals(home:addButton():setText("Add Item"):setSize(12,3):setPosition(2,6):onClick(function() aItemFrame:show() aItemFrame:setFocus() end):show())
  201. buttonVisuals(home:addButton():setText("Remove Item"):setSize(12,3):setPosition(2,10):onClick(function() rItemFrame:show() rItemFrame:setFocus() end):show())
  202.  
  203. local function StringSeperate(str, seperator)
  204. local words = {}
  205. local word = ""
  206.  
  207.     if(string.sub(str, str:len(), str:len())~=seperator)then
  208.         str = str..""..seperator        
  209.     end
  210.     for x=1,str:len() do
  211.         local s = string.sub(str,x,x)
  212.         if(s==seperator)then
  213.             table.insert(words, word)
  214.             word = ""
  215.         else
  216.             word = word..s
  217.         end
  218.     end
  219.     return words
  220. end
  221.  
  222. if not(fs.exists("recipes"))then
  223.     fs.open("recipes","w").close()
  224. end
  225.  
  226. local f = fs.open("recipes", "r")
  227. for line in f.readLine do
  228.     local tab = StringSeperate(line, "|")
  229.     if(tab[1]~=nil)and(tab[2]~=nil)and(tab[3]~=nil)and(tab[4]~=nil)and(tab[5]~=nil)then
  230.         logging("Registered recipe: "..tab[3].."x "..tab[1]..":"..tab[2])
  231.         local recipe = {name=tab[1],damage=tonumber(tab[2]),minAmount=tonumber(tab[3]),maxCraftAmount=tonumber(tab[4]),fails=0,timer=0}
  232.         if(tab[5]=="true")then
  233.             recipe.useDmg=true
  234.         else
  235.             recipe.useDmg=false
  236.         end
  237.         rList:addItem(recipe.minAmount.."x "..recipe.name..":"..recipe.damage, nil, nil, recipe)
  238.         table.insert(recipeList, recipe)
  239.     end
  240. end
  241. f.close()
  242.  
  243. local function findKeyWithItemName(table, itemname, damage)
  244.     for k,v in pairs(table)do
  245.         if(v.name==itemname)and(v.damage == damage)then
  246.             return k
  247.         end
  248.     end
  249.     return nil
  250. end
  251.  
  252. local scanChestBtn = home:addButton("scanChest"):setText("Scan Chest"):setSize(12,3):setPosition(2,2):show()
  253. local function checkChestForNewEntrys()
  254.     scanChestBtn:setText("Scanning..")
  255.     local inventory = peripheral.find("minecraft:chest")
  256.     local items = {}
  257.     local itemAmounts = {}
  258.     local somethingChanged = false
  259.  
  260.         if(inventory~=nil)then
  261.             for x=1,inventory.size(), 1 do
  262.                 local item = inventory.getItemDetail(x)
  263.                 if(item~=nil)then
  264.                     if(item.damage==nil)then item.damage = 0 end
  265.                     table.insert(items, item)
  266.                 end
  267.                 os.sleep(0.1)
  268.             end
  269.         else
  270.             logging("No chest available!")
  271.         end
  272.      
  273.         if(#items > 0)then
  274.             for _,v in pairs(items)do
  275.                 local key = findKeyWithItemName(itemAmounts, v.name, v.damage)
  276.                 if(key~=nil)then
  277.                     itemAmounts[key].count = itemAmounts[key].count + v.count
  278.                 else
  279.                     table.insert( itemAmounts, {name=v.name, damage=v.damage, count = v.count})
  280.                 end    
  281.             end
  282.         end
  283.      
  284.         if(#itemAmounts > 0)then
  285.             for _,v in pairs(itemAmounts)do
  286.                 local key = findKeyWithItemName(recipeList, v.name, v.damage)
  287.                 if(key~=nil)then
  288.                     if(recipeList[key].minAmount ~= v.count)then
  289.                         logging("Edited recipe: "..v.name.. ":"..v.damage.." new count: "..v.count)
  290.                     end
  291.                     somethingChanged = true
  292.                     recipeList[key].minAmount = v.count
  293.                 else
  294.                     table.insert( recipeList, {name=v.name, damage=v.damage, minAmount = v.count, maxCraftAmount = 0, useDmg = true, fails = 0, timer = 0})
  295.                     somethingChanged = true
  296.                     logging("Registered recipe: "..v.count.."x "..v.name.. ":"..v.damage)
  297.                 end
  298.             end
  299.             if(somethingChanged)then
  300.                 SaveToFile()
  301.             end
  302.         end
  303.     scanChestBtn:setText("Scan Chest")
  304.     logging("Scanning chest done.")
  305. end
  306.  
  307. local chestScanThread = main:addThread("chestScanThread")
  308. buttonVisuals(scanChestBtn:onClick(function() chestScanThread:start(checkChestForNewEntrys) end))
  309.  
  310.  
  311. local function GetAmount(itemAmount, recipe)
  312.     local amount = 0
  313.     if(itemAmount < recipe.minAmount)then
  314.         if(recipe.maxCraftAmount > 0)then
  315.             if(recipe.minAmount-itemAmount > recipe.maxCraftAmount)then
  316.                 amount = recipe.maxCraftAmount
  317.             else
  318.                 amount = recipe.minAmount-itemAmount
  319.             end
  320.         else
  321.             amount = recipe.minAmount-itemAmount
  322.         end
  323.     end
  324.     return amount
  325. end
  326.    
  327. function GetRecipeKey(pattern)
  328.     for k,v in pairs(recipeList)do
  329.         if(v.name == pattern.name)then
  330.             if(pattern.damage==nil)then return k end
  331.             if(v.useDmg)then
  332.                 if(v.damage == pattern.damage)then
  333.                     return k
  334.                 end
  335.             else
  336.                 return k
  337.             end
  338.         end
  339.     end
  340.     return nil
  341. end
  342.  
  343. local function CheckCraftingRecipe(recipe)
  344.     local pattern = bridge.getItem({name=recipe.name})
  345.     local item = {pattern=pattern, amount=0}
  346.     if(pattern~=nil)then
  347.       local storedAmount = pattern.amount
  348.       local neededItemAmount = GetAmount(storedAmount, recipe)
  349.       if(neededItemAmount > 0)then
  350.         item.amount = neededItemAmount
  351.         table.insert(craftingQueue, item)
  352.         return true
  353.       end
  354.     end
  355.     return false
  356. end
  357.  
  358. function RemoveRecipe(item)
  359.     local key = -1
  360.         for k,v in pairs(recipeList)do
  361.             if(v.name == item.name)and(v.damage== item.damage)then
  362.                 key = k
  363.             end
  364.         end
  365.         if(key>=0)then
  366.             table.remove(recipeList, key)
  367.         end
  368.         SaveToFile()
  369. end
  370.  
  371. local function FindKeyInTable(table, item)
  372.     for k,v in pairs(table)do
  373.         if(v==item)then
  374.             return k
  375.         end
  376.     end
  377.     return nil
  378. end
  379.  
  380. local function CheckAllRecipes()
  381.     for _,v in pairs(recipeList)do
  382.         if(type(v)=="table")then
  383.             CheckCraftingRecipe(v)
  384.         end
  385.     end
  386. end
  387.  
  388. local function jobCrafting(coworker, item)
  389.     if(jobList:getItem(coworker)~=nil)then
  390.         jobList:editItem(coworker, "Co-Worker "..coworker..": "..item.amountToCraft.."x "..item.item.displayName:gsub(" ", ""))
  391.     else
  392.         jobList:addItem("Co-Worker "..coworker..": "..item.amountToCraft.."x "..item.item.displayName:gsub(" ", ""))
  393.     end
  394.  
  395. end
  396.  
  397. local function jobDone(coworker)
  398.     if(jobList:getItem(coworker)~=nil)then
  399.         jobList:editItem(coworker, "Co-Worker "..coworker..": waiting...")
  400.     else
  401.         jobList:addItem("Co-Worker "..coworker..": waiting...")
  402.     end
  403. end
  404.  
  405. local coWorkerId = 1
  406. local function UpdateCraftingQueue()
  407.     while(#craftingQueue > 0)do
  408.         local activeCoWorkers = {}
  409.         local craftingQueuesToRemove = {}
  410.         for _,v in pairs(craftingQueue)do
  411.             if(#activeCoWorkers+1 <= maxCoWorker)then
  412.                 local stack = v.pattern
  413.                 local recipeKey = GetRecipeKey(stack)
  414.  
  415.                 local waittimer = 0
  416.                 local multiplier = 1
  417.  
  418.                 if(recipeList[recipeKey].fails > 0)and(recipeList[recipeKey].fails <=10)then
  419.                     multiplier = recipeList[recipeKey].fails
  420.                 elseif(recipeList[recipeKey].fails > 10)then
  421.                     multiplier = 20
  422.                 end
  423.                 waittimer = multiplier * 30
  424.                 if(os.clock()>=recipeList[recipeKey].timer+waittimer)then
  425.                     if not(bridge.isItemCrafting(stack.name))then
  426.                             local currentItemState = {item=stack, curAmount = stack.count, amountToCraft = v.amount}
  427.                         if(bridge.isItemCraftable({name=stack.name}))then
  428.                             local task, errormsg = bridge.craftItem({name=stack.name, count = v.amount})
  429.                             if(task)then
  430.                                 logging("Sheduled Task: "..v.amount.." ("..stack.name..") "..stack.displayName:gsub(" ", ""))
  431.                                 jobCrafting(coWorkerId, currentItemState)
  432.                                 currentItemState.coWorker = coWorkerId
  433.                                 coWorkerId = coWorkerId + 1
  434.                                 if(coWorkerId > maxCoWorker)then coWorkerId = 1 end
  435.                                 table.insert(activeCoWorkers, currentItemState)
  436.                                 recipeList[recipeKey].fails = 0
  437.                             else
  438.                                 logging("Error sheduling task: "..v.amount.."x ("..stack.name..") "..stack.displayName:gsub(" ", ""))
  439.                                 logging("Not enough materials!")
  440.                                 recipeList[recipeKey].fails = recipeList[recipeKey].fails + 1
  441.                                 recipeList[recipeKey].timer = os.clock()
  442.                             end
  443.                         else
  444.                             logging("Error sheduling task: "..v.amount.."x ("..stack.name..") "..stack.displayName:gsub(" ", ""))
  445.                             logging("No pattern available!")
  446.                             recipeList[recipeKey].fails = recipeList[recipeKey].fails + 1
  447.                             recipeList[recipeKey].timer = os.clock()
  448.                         end
  449.                     end
  450.                 end
  451.                 table.insert(craftingQueuesToRemove, v)
  452.             end
  453.         end
  454.  
  455.         if(#craftingQueuesToRemove > 0)then
  456.             for _,v in pairs(craftingQueuesToRemove)do
  457.                 local id = FindKeyInTable(craftingQueue, v)
  458.                 table.remove(craftingQueue, id)
  459.             end
  460.         end
  461.  
  462.         while(#activeCoWorkers > 0)do
  463.             local finishedCoworker = {}
  464.             for _,v in pairs(activeCoWorkers)do
  465.                 if not(bridge.isItemCrafting(v.item.name))then
  466.                     logging("Task done: "..v.amountToCraft.."x ("..v.item.name..") "..v.item.displayName:gsub(" ", ""))
  467.                     table.insert(finishedCoworker, v)
  468.                 end
  469.             end
  470.             if(#finishedCoworker>0)then
  471.                 for _,v in pairs(finishedCoworker)do
  472.                     local id = FindKeyInTable(activeCoWorkers, v)
  473.                     table.remove(activeCoWorkers, id)
  474.                     jobDone(v.coWorker)
  475.                 end
  476.             end
  477.             os.sleep(0.75)
  478.         end
  479.         os.sleep(0.75)
  480.     end
  481. end
  482.  
  483. main:addThread("craftingThread"):start(function() while true do CheckAllRecipes() os.sleep(1) UpdateCraftingQueue() os.sleep(1) end end)
  484.  
  485. logging("Autocrafter successfully loaded!")
  486.  
  487. basalt.autoUpdate()
Advertisement
RAW Paste Data Copied
Advertisement