Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local turtleName = "turtle_2"
- -- Load dependancies
- if not fs.exists("list") then
- shell.run("pastebin", "get", "NnxPk3Dt", "list")
- end
- -- Load dependancies
- if not fs.exists("recipeRecorder") then
- shell.run("pastebin", "get", "wfvywJmg", "recipeRecorder")
- end
- -- Load API
- if not fs.exists("API") then
- shell.run("pastebin", "get", "EzkfU5ZM", "API")
- end
- shaka = require("API")
- -- Variables for peripherals
- local wirelessModem = nil
- local wiredModem = nil
- local monitor = nil
- local fromInventories = {}
- local itemName = nil
- local listExist = false
- if not fs.exists("items_list.lua") then
- shaka.clearScreen()
- term.setTextColor(colors.green)
- print("Welcome!")
- sleep(1)
- term.setCursorPos(1, 3)
- term.setTextColor(colors.yellow)
- textutils.slowPrint("Please add crafting recipes...", 10)
- sleep(1)
- shell.run("recipeRecorder")
- else
- listExist = true
- end
- -- Connect peripherals on direct sides
- local function connectDirectPeripherals()
- local sides = {"left", "right", "top", "bottom", "front", "back"}
- for _, side in ipairs(sides) do
- local device = peripheral.getType(side)
- if device == "modem" then
- local modem = peripheral.wrap(side)
- if modem.isWireless() then
- wirelessModem = modem
- rednet.open(side)
- else
- wiredModem = modem
- rednet.close(side)
- end
- elseif device == "monitor" then
- monitor = peripheral.wrap(side)
- end
- end
- end
- -- Function to check if a table contains an item
- local function tableContains(t, item)
- for _, value in pairs(t) do
- if value == item then
- return true
- end
- end
- return false
- end
- -- Connect and bind inventory peripherals via modem
- local function getInventories()
- if not wiredModem then
- print("No wired modem detected. Cannot fetch inventories.")
- return
- end
- local remotePeripherals = wiredModem.getNamesRemote()
- for _, inventoryName in ipairs(remotePeripherals) do
- if inventoryName and not shaka.stringFind(inventoryName, "turtle") and not shaka.stringFind(inventoryName, "computer") then
- if not tableContains(fromInventories, inventoryName) then
- table.insert(fromInventories, inventoryName)
- end
- end
- end
- shaka.writeFile("inventories", fromInventories)
- end
- local function startup()
- connectDirectPeripherals()
- getInventories()
- if monitor then
- monitor.write("Setup Complete. Inventories saved.")
- else
- -- print("Setup Complete. Inventories saved.")
- end
- end
- startup()
- -- Function to search an individual inventory for the desired item and return a list of slots with amounts
- local function searchInventoryForSlots(inventoryName, itemName)
- local inventory = peripheral.wrap(inventoryName)
- local slots = {}
- if inventory then
- local items = inventory.list()
- for slot, details in pairs(items) do
- if details.name == itemName then
- table.insert(slots, {slot = slot, count = details.count})
- end
- end
- end
- return slots
- end
- -- Function to search all inventories and return a list of slots with the desired item
- local function searchAllInventories(itemName)
- local indexedSlots = {}
- local tasks = {}
- for _, inventoryName in ipairs(fromInventories) do
- table.insert(tasks, function()
- local slots = searchInventoryForSlots(inventoryName, itemName)
- if #slots > 0 then
- indexedSlots[inventoryName] = slots
- end
- -- Print inventory and slot info for debugging
- for _, slotInfo in ipairs(slots) do
- -- print(inventoryName .. " has " .. slotInfo.count .. " of " .. itemName .. " in slot " .. slotInfo.slot)
- end
- end)
- end
- parallel.waitForAll(unpack(tasks))
- -- shaka.writeFile("lol", indexedSlots)
- return indexedSlots
- end
- -- Function to pull items from the indexed slots
- local function pullItemsFromSlots(indexedSlots, quantity, toSlot)
- local totalPulled = 0
- local remainingToPull = quantity
- local pullTasks = {}
- -- Create parallel tasks to pull from each slot
- for inventoryName, slots in pairs(indexedSlots) do
- for _, slotInfo in ipairs(slots) do
- local toPull = math.min(slotInfo.count, remainingToPull)
- table.insert(pullTasks, function()
- local inventory = peripheral.wrap(inventoryName)
- local pulled = 0
- if inventory then
- pulled = inventory.pushItems(turtleName, slotInfo.slot, toPull, toSlot)
- totalPulled = totalPulled + pulled
- remainingToPull = remainingToPull - pulled
- -- print("Pulled " .. pulled .. " from " .. inventoryName .. " (slot " .. slotInfo.slot .. ")")
- end
- end)
- remainingToPull = remainingToPull - toPull
- if remainingToPull <= 0 then
- break
- end
- end
- end
- -- Run all the tasks in parallel
- parallel.waitForAll(unpack(pullTasks))
- if totalPulled >= quantity then
- -- print("Successfully pulled " .. totalPulled .. " of " .. itemName)
- return true
- else
- print("Failed to pull enough items. Pulled " .. totalPulled .. " out of " .. quantity)
- return false
- end
- end
- function findAvailableDrop(slot)
- local tasks = {}
- for i = 1, #fromInventories do
- local invWrap = peripheral.wrap(fromInventories[i])
- tasks[#tasks+1] = function()
- invWrap.pullItems(turtleName, slot)
- end
- end
- parallel.waitForAll(unpack(tasks))
- end
- function dropInventory()
- local tasks = {}
- for i = 1, 16 do
- if turtle.getItemCount(i) > 0 then
- tasks[#tasks+1] = function()
- repeat
- findAvailableDrop(i)
- until turtle.getItemCount(i) == 0
- end
- end
- end
- parallel.waitForAll(unpack(tasks))
- end
- -- Load saved recipes
- local function loadRecipes()
- local filePath = "recipes/recipes.lua"
- local recipes = {}
- if fs.exists(filePath) then
- local file = fs.open(filePath, "r")
- local content = file.readAll()
- file.close()
- if content and content ~= "" then
- recipes = textutils.unserialize(content) or {}
- end
- end
- return recipes
- end
- -- Find a recipe by output item
- local function findRecipeByOutput(outputName)
- local recipes = loadRecipes()
- for _, recipe in ipairs(recipes) do
- if recipe.output[1].name == outputName then
- -- print(outputName)
- -- shaka.writeFile("showMe", recipe)
- return recipe
- end
- end
- return nil
- end
- local function checkAvailability(itemName, amount)
- -- Step 1: Search all inventories for available slots for the item
- local indexedSlots = searchAllInventories(itemName)
- local totalAvailable = 0
- -- Step 2: Check if there are enough items in the inventories
- for _, slots in pairs(indexedSlots) do
- for _, slotInfo in ipairs(slots) do
- totalAvailable = totalAvailable + slotInfo.count
- end
- end
- -- Step 3: If not enough items, return false
- if totalAvailable < amount then
- -- print("Not enough " .. itemName .. " available! Only " .. totalAvailable .. "/" .. amount .. " found.")
- local missingCount = amount - totalAvailable
- -- print(missingCount)
- -- sleep(2)
- return missingCount
- end
- -- Step 4: If enough items are available, return true
- -- print("There are enough " .. itemName .. " available: " .. totalAvailable .. "/" .. amount)
- return true
- end
- local function checkRecipeAvailability(outputName, amount)
- -- Step 1: Find the recipe for the given output item
- local recipe = findRecipeByOutput(outputName)
- if not recipe then
- print("Recipe for " .. outputName .. " not found.")
- return false, nil, nil
- end
- -- Get the number of items produced by the recipe (e.g., 1 chest)
- local craftOutput = recipe.output[1].count
- -- Step 2: Calculate the total amount of ingredients required based on the amount to craft
- local totalIngredients = {} -- To store the total required quantity of each input item
- for _, inputItem in ipairs(recipe.input) do
- if inputItem.type ~= "empty" then
- -- Calculate the required amount of the input item (scaled by amount if needed)
- local requiredAmount = math.ceil((amount or 1)/craftOutput)
- totalIngredients[inputItem.name] = (totalIngredients[inputItem.name] or 0) + requiredAmount
- end
- end
- -- Step 3: Check if there are enough ingredients available in the inventories
- for itemName, requiredAmount in pairs(totalIngredients) do
- -- print("Checking availability for " .. itemName .. ": " .. requiredAmount .. " needed.")
- -- Check if the required amount of the ingredient is available in the inventories
- local missing = checkAvailability(itemName, requiredAmount)
- if missing ~= true then
- -- print("Missing " .. missing .. " of " .. itemName)
- -- sleep(2)
- return itemName, missing, requiredAmount
- end
- end
- -- Step 4: If all ingredients are available, return true
- -- print("All ingredients are available for " .. outputName)
- return true, amount, nil
- end
- -- Main pull
- local function finalPull(item_Name, amount, toSlot)
- itemName = item_Name
- -- Step 1: Search all inventories for available slots and check if there are enough items
- local indexedSlots = searchAllInventories(item_Name)
- local totalAvailable = 0
- for _, slots in pairs(indexedSlots) do
- for _, slotInfo in ipairs(slots) do
- totalAvailable = totalAvailable + slotInfo.count
- end
- end
- -- print(totalAvailable, amount)
- -- Step 2: If not enough items, abort the pull
- if totalAvailable < amount then
- -- print("Not enough items available! Only " .. totalAvailable .. "/"..amount.." of " .. item_Name .. " found.")
- return false
- end
- -- Step 3: Proceed to pull items from indexed slots
- return pullItemsFromSlots(indexedSlots, math.min(amount, 64), toSlot)
- end
- -- Function to check if all items in the list can be found in the connected inventories with the specified amount
- local function checkAllItemsAvailability(itemsList)
- -- Loop through each item in the list
- for _, item in ipairs(itemsList) do
- local itemName = item.name
- local requiredAmount = item.amount
- -- Check if the item is available in the inventories
- local missingAmount = checkAvailability(itemName, requiredAmount)
- -- If the checkAvailability function returns a number (missing amount), that means we don't have enough items
- if missingAmount ~= true then
- -- print("Not enough " .. itemName .. " available. Missing: " .. missingAmount)
- return itemName, missingAmount
- end
- end
- -- If all items are available with the required amount
- -- print("All items are available with the required amount.")
- return true, true
- end
- -- Function to craft an item based on a requested output
- local function craftItem(outputName, amount)
- -- local amount = math.min(amount, 64)
- -- Step 1: Check availability of ingredients for the requested item
- local name, missAmount, requiredAmount = checkRecipeAvailability(outputName, amount)
- -- print("MISS: ", name, missAmount)
- -- sleep(2)
- if name ~= true then
- if findRecipeByOutput(outputName) ~= nil then
- -- print("Not enough " .. name .. " (" .. missAmount .. "/" .. requiredAmount .. "). Crafting required.")
- craftItem(name, missAmount) -- Recursively craft missing item
- return
- craftItem(outputName, amount)
- else
- print("Missing ", name, " and can't craft ", outputName,", aborting")
- return
- end
- end
- -- Step 2: Find the recipe for the given output item
- local recipe = findRecipeByOutput(outputName)
- if not recipe then
- term.setTextColor(colors.red)
- print("Recipe for " .. outputName .. " not found.")
- sleep(1)
- return
- end
- local craftOutput = recipe.output[1].count
- -- Step 3: Pull the input items using the finalPull function
- -- print("Pulling input items for " .. outputName .. "...")
- for _, inputItem in ipairs(recipe.input) do
- if inputItem.type ~= "empty" then
- -- Pull each item to the turtle's inventory
- local success = finalPull(inputItem.name, math.ceil(amount/craftOutput), inputItem.slot)
- if not success then
- term.setTextColor(colors.red)
- print("Failed to pull item: " .. inputItem.name)
- return
- end
- end
- end
- -- Step 4: Craft the item
- -- print("Crafting " .. outputName .. "...")
- turtle.craft()
- -- Step 5: Check if crafting succeeded
- local output = turtle.getItemDetail(1)
- if output and output.name == outputName then
- term.setTextColor(colors.green)
- print("Crafted " .. outputName)
- else
- term.setTextColor(colors.red)
- print("Crafting failed. Check inputs.")
- end
- -- Drop excess items
- -- sleep(2)
- dropInventory()
- end
- -- Define key mappings for the desired programs
- local keyMappings = {
- c = "recipeRecorder", -- Program to switch to when 'c' is pressed
- f = "list" -- Program to switch to when 'f' is pressed
- }
- -- Function to map keys to program switches
- function programSwitcher()
- shaka.clearScreen()
- term.setTextColor(colors.gray)
- print("[c] to switch to recipeRecorder\n[f] to view list")
- while true do
- local event, keyCode = os.pullEvent("key") -- Wait for a key press
- local keyName = keys.getName(keyCode) -- Get the name of the key pressed
- if keyMappings[keyName] then
- print("Switching to program: " .. keyMappings[keyName])
- shell.run(keyMappings[keyName]) -- Run the specified program
- break -- Exit loop after launching the program
- else
- -- print("Unmapped key pressed: " .. (keyName or "unknown"))
- end
- end
- end
- function doitall()
- local wantedItems = shaka.readFile("items_list.lua")
- while true do
- local wantedName, wantedAmount = checkAllItemsAvailability(wantedItems)
- if wantedName ~= true then
- craftItem(wantedName, wantedAmount)
- end
- sleep(1)
- end
- end
- function finish()
- if listExist then
- parallel.waitForAny(doitall, programSwitcher)
- end
- end
- finish()
- -- dropInventory()
- -- finalPull("minecraft:oak_planks", 3, 5)
- -- craftItem("minecraft:piston", 1)
- -- findRecipeByOutput("minecraft:chest")
- -- searchAllInventories("minecraft:chest")
- -- checkAvailability("minecraft:chest", 3)
- -- checkRecipeAvailability("minecraft:spruce_slab", 6)
Add Comment
Please, Sign In to add comment