Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local promptColor = colors.yellow
- local textColor = colors.white
- local backgroundColor = colors.black
- local errorColor = colors.red
- local successColor = colors.green
- local titleColor = colors.cyan
- local buttonBackgroundColor = colors.red
- local buttonTextColor = colors.black
- local recipes = {}
- local recipeConfigPath = shell.resolve("").."/autocrafting/recipes.config"
- -- structure={
- -- [itemIndexName]={
- -- name=(string),
- -- damageValues={
- -- (int)={
- -- displayName=(string),
- -- recipes={
- -- {
- -- recipe={
- -- [itemIndexName]={
- -- slots={(int),...},
- -- displayName=(string),
- -- name=(string),
- -- damage=(int)
- -- },
- -- ...
- -- },
- -- resultQty=(int)
- -- },
- -- ...
- -- }
- -- },
- -- ...
- -- }
- -- }
- -- }
- local inventories = {}
- local outputInventory = nil
- local recipeInputInventory = nil
- local peripheralConfigPath = shell.resolve("").."/autocrafting/peripherals.config"
- local turtle = nil
- local indexedItems = {}
- -- An item's index name is defined as the item's internal name with all special characters removed
- --
- -- structure={
- -- [itemIndexName]={
- -- name=(string),
- -- damageValues={
- -- [int]={
- -- displayName=(string),
- -- locations={
- -- {
- -- perip=(string) the name of the inventory peripheral that this item can be gotten from,
- -- count=(int) the count of that item in the peripheral's inventory,
- -- slot=(int) the slot the item can be pulled from
- -- },
- -- ...
- -- }
- -- },
- -- ...
- -- }
- -- },
- -- ...
- -- }
- local orderQueue = {}
- -- structure={
- -- {
- -- result=(string) result display name,
- -- missingIngredients=(table) the ingredients required for crafting that were not present and do not have a recipe stored for them{
- -- [itemIndexName]={
- -- displayName=(string),
- -- qtyMissing=(int)
- -- },
- -- ...
- -- }
- -- },
- -- ...
- -- }
- function getItemIndexName(itemName)
- return string.gsub(itemName,"([^%d%l%u])","")
- end
- function resetRecipes()
- recipes = {}
- end
- function saveRecipeConfig()
- local file = fs.open(recipeConfigPath,"w")
- file.writeLine(textutils.serialize(recipes))
- file.close()
- end
- function prepareForSerialize(ob)
- local result = nil
- if type(ob) == "function" then
- result = "function"
- elseif type(ob) == "table" then
- result = {}
- for k,i in pairs(ob) do
- result[k] = prepareForSerialize(i)
- end
- else
- result = ob
- end
- return result
- end
- function savePeripheralConfig()
- local file = fs.open(peripheralConfigPath,"w")
- local tempInventoryAddress = nil
- local outputInventoryAddress = nil
- local recipeInputInventoryAddress = nil
- local recipeInputInventorySlots = nil
- if tempInventory ~= nil then
- tempInventoryAddress = tempInventory.address
- end
- if outputInventory ~= nil then
- outputInventoryAddress = outputInventory.address
- end
- if recipeInputInventory ~= nil then
- recipeInputInventoryAddress = recipeInputInventory.address
- recipeInputInventorySlots = recipeInputInventory.craftingSlots
- end
- local data = {
- tempInventory=tempInventoryAddress,
- outputInventory=outputInventoryAddress,
- recipeInputInventory=recipeInputInventoryAddress,
- recipeInputInventorySlots=recipeInputInventorySlots
- }
- file.writeLine(textutils.serialize(data))
- file.close()
- end
- function indexNetwork()
- local newIndex = {}
- for _,inv in pairs(inventories) do
- local invSize = peripheral.call(inv,"size")
- for slot = 1,invSize,1 do
- local data = peripheral.call(inv,"getItemMeta",slot)
- if data ~= nil then
- local indexName = getItemIndexName(data.name)
- if newIndex[indexName] == nil then
- newIndex[indexName] = {
- name=data.name,
- damageValues={}
- }
- end
- if newIndex[indexName].damageValues[data.damage] == nil then
- newIndex[indexName].damageValues[data.damage] = {
- displayName=data.displayName,
- locations={}
- }
- end
- table.insert(newIndex[indexName].damageValues[data.damage].locations,{
- address=inv,
- slot=slot
- })
- end
- end
- end
- indexedItems = newIndex
- end
- function findTurtle()
- turtle = nil
- for _,p in pairs(peripheral.getNames()) do
- if peripheral.getType(p) == "turtle" then
- peripheral.call(p,"reboot")
- sleep(1)
- local perip = peripheral.wrap(p)
- if perip.getLabel() == "Ready For Crafting" then
- turtle = perip
- turtle.address = p
- return nil
- end
- end
- end
- end
- function isPeripheralAnInventory(address)
- if not peripheral.isPresent(address) then
- return false
- end
- local perip = peripheral.wrap(address)
- if perip.pullItems and type(perip.pullItems) == "function" then
- return true
- end
- return false
- end
- function setUpPeripherals()
- for _,p in pairs(peripheral.getNames()) do
- if peripheral.getType(p) == "modem" then
- rednet.open(p)
- end
- end
- local data = {}
- if fs.exists(peripheralConfigPath) then
- local file = fs.open(peripheralConfigPath,"r")
- data = textutils.unserialize(file.readAll())
- file.close()
- if data == nil then
- data = {}
- end
- end
- outputInventory = nil
- tempInventory = nil
- recipeInputInventory = nil
- inventories = {}
- if data.outputInventory ~= nil and isPeripheralAnInventory(data.outputInventory) then
- outputInventory = peripheral.wrap(data.outputInventory)
- outputInventory.address = data.outputInventory
- else
- if peripheral.isPresent("top") and isPeripheralAnInventory("top") then
- outputInventory = peripheral.wrap("top")
- outputInventory.address = "top"
- else
- term.clear()
- term.setCursorPos(1,1)
- term.setTextColor(titleColor)
- print("AutoCrafting.lua Configurator")
- while outputInventory == nil do
- term.setTextColor(promptColor)
- print("Please connect/reconnect an inventory to the network to serve as an output")
- local e,p = os.pullEvent("peripheral")
- if isPeripheralAnInventory(p) then
- outputInventory = peripheral.wrap(p)
- outputInventory.address = p
- else
- term.setTextColor(errorColor)
- print("Selected peripheral is not a valid inventory:")
- term.setTextColor(textColor)
- print("\""..p.."\"")
- print("")
- end
- end
- end
- end
- if data.tempInventory ~= nil and isPeripheralAnInventory(data.tempInventory) then
- tempInventory = peripheral.wrap(data.tempInventory)
- tempInventory.address = data.tempInventory
- else
- if peripheral.isPresent("bottom") and isPeripheralAnInventory("bottom") then
- tempInventory = peripheral.wrap("bottom")
- tempInventory.address = "bottom"
- else
- term.clear()
- term.setCursorPos(1,1)
- term.setTextColor(titleColor)
- print("AutoCrafting.lua Configurator")
- while tempInventory == nil do
- term.setTextColor(promptColor)
- print("Please connect/reconnect an inventory to the network to serve as a temporary inventory for storing intermediate products")
- local e,p = os.pullEvent("peripheral")
- if isPeripheralAnInventory(p) then
- tempInventory = peripheral.wrap(p)
- tempInventory.address = p
- else
- term.setTextColor(errorColor)
- print("Selected peripheral is not a valid inventory:")
- term.setTextColor(textColor)
- print("\""..p.."\"")
- print("")
- end
- end
- end
- end
- if data.recipeInputInventory ~= nil and isPeripheralAnInventory(data.recipeInputInventory) then
- recipeInputInventory = peripheral.wrap(data.recipeInputInventory)
- recipeInputInventory.address = data.recipeInputInventory
- else
- if peripheral.isPresent("left") and isPeripheralAnInventory("left") then
- recipeInputInventory = peripheral.wrap("left")
- recipeInputInventory.address = "left"
- else
- term.clear()
- term.setCursorPos(1,1)
- term.setTextColor(titleColor)
- print("AutoCrafting.lua Configurator")
- while recipeInputInventory == nil do
- term.setTextColor(promptColor)
- print("Please connect/reconnect an inventory to the network to serve as a recipe input")
- local e,p = os.pullEvent("peripheral")
- if isPeripheralAnInventory(p) then
- local perip = peripheral.wrap(p)
- if perip.size() >= 9 then
- recipeInputInventory = perip
- recipeInputInventory.address = p
- end
- end
- if recipeInputInventory == nil then
- term.setTextColor(errorColor)
- print("Selected peripheral is not a valid inventory:")
- term.setTextColor(textColor)
- print("\""..p.."\"")
- print("")
- end
- end
- end
- end
- if data.recipeInputInventorySlots ~= nil and type(data.recipeInputInventorySlots) == "table" and #data.recipeInputInventorySlots == 9 then
- recipeInputInventory.craftingSlots = {}
- for _,i in ipairs(data.recipeInputInventorySlots) do
- table.insert(recipeInputInventory.craftingSlots,i)
- end
- elseif recipeInputInventory.size() == 9 then
- recipeInputInventory.craftingSlots = {}
- for i=1,9,1 do
- table.insert(recipeInputInventory.craftingSlots,i)
- end
- else
- local slots = {}
- term.clear()
- term.setCursorPos(1,1)
- term.setTextColor(titleColor)
- print("AutoCrafting.lua Configurator")
- while #slots ~= 9 do
- slots = {}
- term.setTextColor(promptColor)
- print("Please put items in the 9 slots of the Recipe Input peripheral that you want to serve as the crafting grid")
- print("Press any key to continue")
- os.pullEvent("key")
- os.pullEvent("key_up")
- for i=1,recipeInputInventory.size(),1 do
- if recipeInputInventory.getItemMeta(i) ~= nil then
- table.insert(slots,i)
- end
- end
- if #slots ~= 9 then
- term.setTextColor(errorColor)
- if #slots < 9 then
- print("Too few slots were found with items in them")
- else
- print("Too many slots were found with items in them")
- end
- print("")
- end
- end
- recipeInputInventory.craftingSlots = slots
- end
- for _,p in pairs(peripheral.getNames()) do
- if p ~= outputInventory.address and
- p ~= tempInventory.address and
- p ~= recipeInputInventory.address and
- isPeripheralAnInventory(p) then
- table.insert(inventories,p)
- end
- end
- savePeripheralConfig()
- end
- if fs.exists(recipeConfigPath) then
- local file = fs.open(recipeConfigPath,"r")
- recipes = textutils.unserialize(file.readAll())
- file.close()
- if recipes == nil then
- resetRecipes()
- saveRecipeConfig()
- end
- else
- saveRecipeConfig()
- end
- setUpPeripherals()
- while turtle == nil do
- findTurtle()
- if turtle == nil then
- sleep(1)
- end
- end
- indexNetwork()
- local termWidth,termHeight = term.getSize()
- local currentView = nil
- local windows = {}
- local running = true
- local paused = false
- function putItemInTurtle(sourceInventory,sourceSlot,quantity,turtleSlot)
- local slot = turtleSlot
- if slot >= 7 then
- slot = slot + 2
- elseif slot >= 4 then
- slot = slot + 1
- end
- if type(sourceInventory) == "table" then
- return sourceInventory.pushItems(turtle.address,sourceSlot,quantity,slot)
- else
- return peripheral.call(sourceInventory,"pushItems",turtle.address,sourceSlot,quantity,slot)
- end
- end
- function pullItemFromTurtle(toInventory,turtleSlot,quantity,toSlot)
- local slot = turtleSlot
- if slot >= 7 then
- slot = slot + 2
- elseif slot >= 4 then
- slot = slot + 1
- end
- if type(toInventory) == "table" then
- return toInventory.pullItems(turtle.address,slot,quantity,toSlot)
- else
- return peripheral.call(toInventory,"pullItems",turtle.address,slot,quantity,toSlot)
- end
- end
- function addRecipe()
- paused = true
- rednet.receive("paused")
- local recipe = {}
- term.setCursorPos(1,4)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- for i=1,9,1 do
- local meta = recipeInputInventory.getItemMeta(recipeInputInventory.craftingSlots[i])
- if meta ~= nil then
- local indexName = getItemIndexName(meta.name)
- if recipe[indexName] == nil then
- recipe[indexName] = {
- slots={},
- displayName=meta.displayName,
- name=meta.name,
- damage=meta.damage
- }
- end
- table.insert(recipe[indexName].slots,i)
- putItemInTurtle(recipeInputInventory,recipeInputInventory.craftingSlots[i],1,i)
- print(meta.displayName)
- end
- end
- rednet.send(turtle.getID(),turtle.getID(),"craft")
- print("sent command")
- local returnValue = true
- while true do
- local senderId,message,protocol = rednet.receive()
- if protocol == "craft_done" then
- print("received message")
- if message ~= nil then
- print("crafting successful")
- local qty = recipeInputInventory.pullItems(turtle.address,16,64,recipeInputInventory.craftingSlots[5])
- local meta = recipeInputInventory.getItemMeta(recipeInputInventory.craftingSlots[5])
- local resultIndex = getItemIndexName(meta.name)
- if recipes[resultIndex] == nil then
- recipes[resultIndex] = {
- name=meta.name,
- damageValues={}
- }
- end
- if recipes[resultIndex].damageValues[meta.damage] == nil then
- recipes[resultIndex].damageValues[meta.damage] = {
- displayName=meta.displayName,
- recipes={}
- }
- end
- table.insert(recipes[resultIndex].damageValues[meta.damage].recipes,{
- resultQty=qty,
- recipe=recipe
- })
- saveRecipeConfig()
- returnValue = true
- else
- print("crafting failed")
- for i=1,9,1 do
- pullItemFromTurtle(recipeInputInventory,i,64,recipeInputInventory.craftingSlots[i])
- end
- returnValue = false
- end
- break
- end
- end
- paused = false
- rednet.send(os.getComputerID(),"","continue")
- return returnValue
- end
- function switchView(view)
- if windows[view] ~= nil then
- if currentView ~= nil then
- windows[currentView].setVisible(false)
- end
- windows[view].setVisible(true)
- currentView = view
- end
- end
- function createView(name,data)
- local win = window.create(term.current(),1,1,termWidth,termHeight,false)
- win.name = name
- win.extraRender = data.render
- win.extraOnload = data.onload
- win.buttons = {}
- win.panels = {}
- win.onload = function(win)
- win.extraOnload(win)
- win.render(win)
- end
- win.render = function(win)
- win.extraRender(win)
- for _,p in pairs(win.panels) do
- p.render(win,p)
- end
- for _,b in pairs(win.buttons) do
- b.render(win,b)
- end
- end
- for k,v in ipairs(data) do
- if k ~= "render" and k ~= "onload" then
- if win[k] == nil then
- win[k] = v
- end
- end
- end
- for k,b in pairs(data.buttons) do
- local w = string.len(b.text)
- if b.width ~= nil then
- w = b.width
- end
- local button = window.create(win,b.x,b.y,w,1,true)
- button.text = b.text
- if b.render ~= nil then
- button.render = b.render
- else
- button.render = function(win,button)
- button.setCursorPos(1,1)
- button.setTextColor(buttonTextColor)
- button.setBackgroundColor(buttonBackgroundColor)
- button.write(button.text)
- end
- end
- button.onclick = b.onclick
- win.buttons[k] = button
- end
- win.render(win)
- windows[name] = win
- end
- function createWindows()
- createView("main",{
- render=function(win)
- win.setBackgroundColor(backgroundColor)
- win.clear()
- win.setCursorPos(1,1)
- win.setBackgroundColor(colors.gray)
- win.setTextColor(colors.black)
- win.clearLine(1)
- win.write("AutoCrafting - Main Menu")
- end,
- buttons={
- closeButton={
- text="Close",
- x=termWidth-4,
- y=1,
- onclick=function(win) running = false end
- },
- addRecipeButton={
- text="Add Recipe",
- x=2,
- y=3,
- onclick=function(win) switchView("add_recipe") end
- }
- }
- })
- createView("add_recipe",{
- render = function(win)
- win.setBackgroundColor(backgroundColor)
- win.setTextColor(promptColor)
- win.clear()
- win.setCursorPos(2,3)
- print("Please use the Recipe Input device to specify the new recipe")
- win.setCursorPos(1,1)
- win.setBackgroundColor(colors.gray)
- win.setTextColor(colors.black)
- win.clearLine(1)
- win.write("AutoCrafting - Add New Recipe")
- end,
- buttons={
- cancelButton={
- text="Cancel",
- x=termWidth-5,
- y=1,
- onclick=function(win) switchView("main") end
- },
- submitButton={
- text="Submit",
- x=termWidth-6,
- y=termHeight-1,
- onclick=function(win)
- addRecipe()
- switchView("main")
- end
- }
- }
- })
- end
- function main()
- createWindows()
- switchView("main")
- while running do
- local e,p1,p2,p3,p4,p5 = os.pullEvent()
- if e == "mouse_click" then
- local mouseButton,x,y = p1,p2,p3
- term.setCursorPos(1,4)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- for _,b in pairs(windows[currentView].buttons) do
- local bx,by = b.getPosition()
- local bw,bh = b.getSize()
- if x >= bx and y >= by and x < bx+bw and y < by+bh then
- b.onclick()
- break
- end
- end
- end
- end
- rednet.send(turtle.getID(),"","terminate_autocraft")
- term.setCursorPos(1,1)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- end
- function processQueue()
- while running do
- if #orderQueue > 0 then
- indexNetwork()
- local completedOrders = {}
- for _,i in pairs(orderQueue) do
- if paused then
- rednet.send(os.getComputerID(),"","paused")
- rednet.receive("continue")
- end
- end
- else
- if paused then
- rednet.send(os.getComputerID(),"","paused")
- rednet.receive("continue")
- end
- sleep(1)
- end
- end
- end
- parallel.waitForAll(main,processQueue)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement