Guest User

Untitled

a guest
Nov 15th, 2024
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 46.82 KB | None | 0 0
  1. local class = require "artist.lib.class"
  2. local Crafting = class "artist.custom.crafting"  ---@class Crafting
  3.  
  4. local json = require 'json'
  5. local have_enough
  6. local log
  7. local load_crafting_status
  8. local count_active_custom_crafts_for_devices
  9. local save_crafting_status
  10. local do_craft
  11. local pretty = require "cc.pretty"
  12. local items
  13. local get_amount
  14. local try_multi_craft
  15. local save_reserved
  16. local have_enough_simp
  17. local check_done = true
  18. local inserting = false
  19. local reserving = false
  20.  
  21.  
  22. local file = io.open(shell.dir().."/crafting_status.json", "w")
  23. file:write("{}")
  24. file:close()
  25. local file = io.open(shell.dir().."/log.txt", "w")
  26. file:write("")
  27. file:close()
  28.  
  29. -- Load the recipes from the file
  30. local function load_recipes()
  31.     local file = io.open(shell.dir().."/recipes.json", "r")
  32.     if file then
  33.         local content = file:read("*a")
  34.         file:close()
  35.         return json.decode(content)
  36.     else
  37.         return {}
  38.     end
  39. end
  40.  
  41. function count_active_custom_crafts_for_devices(devices)
  42.     local crafting_status = load_crafting_status()
  43.     local active_crafts = 0
  44.     for _, process in ipairs(crafting_status) do
  45.         if process.recipe.devices then
  46.             for device, _ in pairs(devices) do
  47.                 if process.recipe.devices[device] and process.status == "in_progress" then
  48.                     active_crafts = active_crafts + 1
  49.                 end
  50.             end
  51.         end
  52.     end
  53.  
  54.     return active_crafts
  55. end
  56.  
  57.  
  58. local function count_active_crafts_for_input(input_c)
  59.     local crafting_status = load_crafting_status()
  60.     local active_crafts = 0
  61.     for _, process in ipairs(crafting_status) do
  62.         if process.recipe.input_c == input_c and process.status == "in_progress" then
  63.             active_crafts = active_crafts + 1
  64.         end
  65.     end
  66.  
  67.     return active_crafts
  68. end
  69.  
  70.  
  71. local function is_crafting_busy(recipe)
  72.     local crafting_status = load_crafting_status()
  73.     if not crafting_status or not crafting_status.recipe then
  74.         return false
  75.     end
  76.         if recipe.multi_craft then       
  77.             local active_crafts_input = count_active_crafts_for_input(recipe.input_c)
  78.         if active_crafts_input >= recipe.multi_limit then
  79.             return true -- Input chest multi-craft limit reached
  80.         end
  81.  
  82.  
  83.         if recipe.devices then
  84.             local active_crafts_devices = count_active_custom_crafts_for_devices(recipe.devices)
  85.             if active_crafts_devices >= recipe.multi_limit then
  86.                 return true
  87.             end
  88.         end
  89.  
  90.  
  91.         for device, _ in pairs(recipe.devices) do
  92.             for _, process in ipairs(crafting_status) do
  93.                 if process.recipe.devices and process.recipe.devices[device] and process.status == "in_progress" and process.recipe.name ~= recipe.name then
  94.                     return true -- Device is in use by another crafting process with a different recipe
  95.                 end
  96.             end
  97.         end
  98.     else
  99.  
  100.         for _, process in ipairs(crafting_status) do
  101.             if process.recipe.input_c == recipe.input_c and process.status == "in_progress" then
  102.                 return true
  103.             end
  104.         end
  105.  
  106.  
  107.         if recipe.devices then
  108.             for device, _ in pairs(recipe.devices) do
  109.                 for _, process in ipairs(crafting_status) do
  110.                     if process.recipe.devices and process.recipe.devices[device] and process.status == "in_progress" then
  111.                         return true
  112.                     end
  113.                 end
  114.             end
  115.         end
  116.     end
  117.  
  118.     return false
  119. end
  120.  
  121.  
  122. function save_crafting_status(status)
  123.     -- Ensure that 'status' is always a list (array)
  124.     if type(status) ~= "table" or status[1] == nil then
  125.         if status[1] == nil then
  126.             status = {}
  127.         else
  128.             status = {status}
  129.         end
  130.     end
  131.  
  132.     local file = io.open(shell.dir().."/crafting_status.json", "w")
  133.  
  134.     file:write(json.encode(status))
  135.     file:close()
  136. end
  137.  
  138.  
  139.  
  140. function load_crafting_status()
  141.     local file = io.open(shell.dir().."/crafting_status.json", "r")
  142.     if file then
  143.         local content = file:read("*a")
  144.         file:close()
  145.         local status = json.decode(content)
  146.  
  147.         return type(status) == "table" and status or {}
  148.     else
  149.         return {}
  150.     end
  151. end
  152.  
  153.  
  154. function log_status()
  155.     local crafting_status = load_crafting_status()
  156.     log("Current crafting status: " .. json.encode(crafting_status))
  157. end
  158. tags = {
  159.     ['minecraft:logs'] = {'minecraft:oak_log', 'minecraft:birch_log'}
  160. }
  161.  
  162.  
  163. function has_enough_item_or_tag(item_or_tag, count)
  164.     if type(item_or_tag) == "table" and item_or_tag.tags then
  165.  
  166.         for _, tag in ipairs(item_or_tag.tags) do
  167.             if type(tag) == "string" then
  168.                 if have_enough(tag, count) then
  169.                     return true
  170.                 end
  171.             end
  172.             for _, tag_item in ipairs(tags[tag] or {}) do
  173.                 if have_enough(tag_item, count) then
  174.                     return true
  175.                 end
  176.             end
  177.         end
  178.     else
  179.  
  180.         return have_enough(item_or_tag, count)
  181.     end
  182.     return false
  183. end
  184.  
  185. function extract_and_merge_items_scheme(scheme)
  186.     local extractedItems = {}
  187.  
  188.     for row = 1, #scheme do
  189.         for col = 1, #scheme[row] do
  190.             local item = scheme[row][col]
  191.  
  192.             if type(item) == "table" and #item > 1 and type(item[2]) == "table" and item[2].count then
  193.                 local itemName = item[1]
  194.                 local quantity = item[2].count or 1  -- Default count to 1 if not specified
  195.  
  196.  
  197.                 if extractedItems[itemName] then
  198.                     extractedItems[itemName] = extractedItems[itemName] + quantity
  199.                 else
  200.                     extractedItems[itemName] = quantity
  201.                 end
  202.             end
  203.         end
  204.     end
  205.  
  206.  
  207.     local result = {}
  208.     for itemName, quantity in pairs(extractedItems) do
  209.         table.insert(result, {itemName, quantity})
  210.     end
  211.  
  212.     return result
  213. end
  214.  
  215. function extract_and_merge_from_devices(devices)
  216.     local mergedItems = {}
  217.  
  218.     for _, slots in pairs(devices) do
  219.         for _, itemData in pairs(slots) do
  220.             if type(itemData) == "table" and itemData[2] and type(itemData[2]) == "table" then
  221.                 local itemName = itemData[1]
  222.                 local requiredCount = itemData[2].count or 1 -- Default to 1 if count is not specified
  223.  
  224.  
  225.                 if mergedItems[itemName] then
  226.                     mergedItems[itemName] = mergedItems[itemName] + requiredCount
  227.                 else
  228.                     mergedItems[itemName] = requiredCount
  229.                 end
  230.             end
  231.         end
  232.     end
  233.  
  234.  
  235.     local result = {}
  236.     for itemName, quantity in pairs(mergedItems) do
  237.         table.insert(result, {itemName, quantity})
  238.     end
  239.  
  240.     return result
  241. end
  242.  
  243. function merge_items(itemList)
  244.     local mergedItems = {}
  245.  
  246.  
  247.     for _, item in ipairs(itemList) do
  248.         local itemName, quantity = item[1], item[2]
  249.  
  250.         if mergedItems[itemName] then
  251.             mergedItems[itemName] = mergedItems[itemName] + quantity
  252.         else
  253.             mergedItems[itemName] = quantity
  254.         end
  255.     end
  256.  
  257.  
  258.     local result = {}
  259.     for itemName, quantity in pairs(mergedItems) do
  260.         table.insert(result, {itemName, quantity})
  261.     end
  262.  
  263.     return result
  264. end
  265.  
  266. function merge_two_lists(list1, list2)
  267.     local mergedItems = {}
  268.  
  269.  
  270.     local function add_items_to_merged(list)
  271.         for _, item in ipairs(list) do
  272.             local itemName, quantity = item[1], item[2]
  273.  
  274.             if mergedItems[itemName] then
  275.                 mergedItems[itemName] = mergedItems[itemName] + quantity
  276.             else
  277.                 mergedItems[itemName] = quantity
  278.             end
  279.         end
  280.     end
  281.  
  282.  
  283.     add_items_to_merged(list1)
  284.     add_items_to_merged(list2)
  285.  
  286.  
  287.     local result = {}
  288.     for itemName, quantity in pairs(mergedItems) do
  289.         table.insert(result, {itemName, quantity})
  290.     end
  291.  
  292.     return result
  293. end
  294.  
  295. local used_items = {}
  296. function save_reserved(crafting_status)
  297.     local data = {}
  298.     local recipes = load_recipes()
  299.     for _, process in ipairs(crafting_status) do
  300.         if process.recipe then
  301.             local rs
  302.             if process.recipe.scheme then
  303.                 rs = extract_and_merge_items_scheme(process.recipe.scheme)
  304.             elseif process.recipe.devices then
  305.                 rs = extract_and_merge_from_devices(process.recipe.devices)
  306.             end
  307.             log(pretty.pretty(rs))
  308.             if rs then
  309.                 merge_two_lists(data,rs)
  310.             end
  311.         end
  312.     end
  313.     log(pretty.pretty(data))
  314.     used_items = data
  315. end
  316.  
  317. function get_count_by_name(itemList, itemName)
  318.     for _, item in ipairs(itemList) do
  319.         if item[1] == itemName then
  320.             return item[2]
  321.         end
  322.     end
  323.     return 0
  324. end
  325.  
  326. function get_missing_from_scheme(scheme)
  327.     local mergedItems = {}
  328.  
  329.  
  330.     for row = 1, #scheme do
  331.         for col = 1, #scheme[row] do
  332.             local item = scheme[row][col]
  333.             if type(item) == "table" then
  334.                 local itemName = item[1]
  335.                 local requiredCount = item[2].count or 1
  336.  
  337.  
  338.                 if mergedItems[itemName] then
  339.                     mergedItems[itemName] = mergedItems[itemName] + requiredCount
  340.                 else
  341.                     mergedItems[itemName] = requiredCount
  342.                 end
  343.             end
  344.         end
  345.     end
  346.  
  347.  
  348.     local result = {}
  349.     for itemName, quantity in pairs(mergedItems) do
  350.         if not has_enough_item_or_tag(itemName, (quantity + get_count_by_name(used_items,itemName))) then
  351.             table.insert(result, {itemName, (quantity + get_count_by_name(used_items,itemName))})
  352.         end
  353.     end
  354.  
  355.     return result
  356. end
  357.  
  358.  
  359.  
  360. function craft(item)
  361.     local recipes = load_recipes()
  362.    
  363.  
  364.     local recipe_found = false
  365.  
  366.  
  367.     for _, recipe in pairs(recipes.crafting) do
  368.         if recipe.result == item then
  369.             craft_crafting_recipe(recipe)
  370.             recipe_found = true
  371.             break
  372.         end
  373.     end
  374.    
  375.     if not recipe_found then
  376.         for _, recipe in pairs(recipes.custom) do
  377.             if recipe.result == item then
  378.                 craft_custom_recipe(recipe)
  379.                 recipe_found = true
  380.                 break
  381.             end
  382.         end
  383.     end
  384.  
  385.  
  386.     if not recipe_found then
  387.         log("not enough "..item)
  388.         log("in craft")
  389.     end
  390. end
  391.  
  392. local function aggregate_missing_items(missing_items)
  393.     local aggregated = {}
  394.     for _, item in ipairs(missing_items) do
  395.         local item_name = item[1]
  396.         local required_count = item[2]
  397.        
  398.         if not aggregated[item_name] then
  399.             aggregated[item_name] = required_count
  400.         else
  401.             aggregated[item_name] = aggregated[item_name] + required_count
  402.         end
  403.     end
  404.     return aggregated
  405. end
  406. local function wait()
  407.     while not check_done do
  408.         os.sleep(0.001)
  409.     end
  410. end
  411.  
  412. function craft_crafting_recipe(recipe)
  413.     parallel.waitForAny(wait, wait)
  414.     inserting = true
  415.     local scheme = recipe['scheme']
  416.     local input_container = recipe['input_c']
  417.     local output_container = recipe['output_c']
  418.     local recipes = load_recipes()  -- Load available recipes
  419.  
  420.     -- Main logic to gather and craft missing items
  421.     local missing_items = aggregate_missing_items(get_missing_from_scheme(scheme))
  422.  
  423.     -- Process each unique missing item
  424.     for item_name, required_count in pairs(missing_items) do
  425.         -- Look for a recipe for the missing item in crafting or custom recipes
  426.         local found_recipe = recipes.crafting[item_name] or recipes.custom[item_name]
  427.        
  428.         if found_recipe then
  429.             -- Calculate the minimum crafting runs needed based on recipe count
  430.             local output_count = found_recipe.count
  431.             local craft_count = math.ceil(required_count / output_count)
  432.            
  433.             log("craft count: " .. tostring(craft_count))
  434.            
  435.             -- Craft just enough to meet the requirement
  436.             local crafted = false
  437.             for i = 1, craft_count do
  438.                 if recipes.crafting[item_name] then
  439.                     crafted = craft_crafting_recipe(recipes.crafting[item_name])
  440.                     log("crafting log")
  441.                 elseif recipes.custom[item_name] then
  442.                     crafted = craft_custom_recipe(recipes.custom[item_name])
  443.                     log("crafting log")
  444.                 end
  445.  
  446.                 -- Stop if sub-crafting fails
  447.                 if not crafted then
  448.                     not_enough({ { item_name, required_count } })
  449.                     inserting = false
  450.                     return false
  451.                 end
  452.             end
  453.         else
  454.             -- No recipe for missing item, so crafting cannot continue
  455.             not_enough({ { item_name, required_count } })
  456.             inserting = false
  457.             return false
  458.         end
  459.     end
  460.  
  461.     -- Crafting device crafting process would be triggered here
  462.     local crafting_status = load_crafting_status()
  463.     table.insert(crafting_status, {
  464.         recipe = recipe,
  465.         type = "crafting",
  466.         status = "busy",
  467.         amount = tostring(get_amount(recipe.result)),
  468.     })
  469.     log("adding craft to list "..recipe.result)
  470.     log(pretty.pretty(crafting_status))
  471.     save_crafting_status(crafting_status)
  472.     inserting = false
  473.     return true  -- Successfully started crafting
  474. end
  475. -- Function to handle custom device recipes with precise sub-recipe crafting
  476. function craft_custom_recipe(recipe)
  477.     parallel.waitForAny(wait, wait)
  478.     inserting = true
  479.  
  480.     local recipes = load_recipes()  -- Load available recipes
  481.  
  482.     -- Check for missing materials and attempt to craft them if necessary
  483.     for device, inputs in pairs(recipe.devices) do
  484.         for slot, input in pairs(inputs) do
  485.             local item = input[1]
  486.             if item ~= "output" then
  487.                 local count = input[2].count
  488.                 local old = item
  489.                 if item.tags then
  490.                     item = item.tags
  491.                 end
  492.  
  493.                 -- Check if the item is available, and handle sub-recipes if it’s missing
  494.                 if not has_enough_item_or_tag(old, count) then
  495.                     local found_recipe = recipes.crafting[old] or recipes.custom[old]
  496.  
  497.                     if found_recipe then
  498.                         -- Calculate minimum crafting runs needed based on recipe count
  499.                         local output_count = found_recipe.count
  500.                         local craft_count = math.ceil(count / output_count)
  501.  
  502.                         -- Craft just enough to meet the requirement
  503.                         local crafted = false
  504.                         for i = 1, craft_count do
  505.                             if recipes.crafting[old] then
  506.                                 crafted = craft_crafting_recipe(recipes.crafting[old])
  507.                             elseif recipes.custom[old] then
  508.                                 crafted = craft_custom_recipe(recipes.custom[old])
  509.                             end
  510.  
  511.                             -- Stop if sub-crafting fails
  512.                             if not crafted then
  513.                                 not_enough({{old, count}})
  514.                                 inserting = false
  515.                                 return false
  516.                             end
  517.                         end
  518.                     else
  519.                         -- No recipe for missing item, so crafting cannot continue
  520.                         not_enough({{old, count}})
  521.                         inserting = false
  522.                         return false
  523.                     end
  524.                 end
  525.             end
  526.         end
  527.     end
  528.  
  529.     -- Custom device crafting process would be triggered here
  530.     local crafting_status = load_crafting_status()
  531.     table.insert(crafting_status, {
  532.         recipe = recipe,
  533.         type = "custom",
  534.         status = "busy",
  535.         amount = tostring(get_amount(recipe.result)),
  536.     })
  537.     save_crafting_status(crafting_status)
  538.     inserting = false
  539.     return true  -- Successfully started crafting
  540. end
  541. function updateCountKeys(t, x)
  542.     for k, v in pairs(t) do
  543.         if type(v) == "table" then
  544.             updateCountKeys(v, x)
  545.         elseif k == "count" then
  546.             t[k] = t[k] * x
  547.         end
  548.     end
  549. end
  550.  
  551. function check_crafting_status()
  552.     log('reload')
  553.     check_done = false
  554.     local crafting_status = load_crafting_status()
  555.     save_reserved(crafting_status)
  556.     while reserving do
  557.         os.sleep(0.0001)
  558.     end
  559.     local updated_status = {}
  560.  
  561.     -- Find the highest existing process_id in crafting_status
  562.     local max_id = 0
  563.     for _, process in ipairs(crafting_status) do
  564.         max_id = math.max(max_id, process.process_id or 0)
  565.     end
  566.  
  567.     -- Assign unique IDs to each process that lacks one
  568.     for _, process in ipairs(crafting_status) do
  569.         if not process.process_id then
  570.             max_id = max_id + 1
  571.             process.process_id = max_id
  572.         end
  573.     end
  574.  
  575.     -- First pass: mark processes and set flags
  576.     for _, process in ipairs(crafting_status) do
  577.         if process.status == 'in_progress' and not process.processed then
  578.             local recipe = process.recipe
  579.             if recipe then
  580.                 log("Processing 'in_progress' recipe: " .. pretty.pretty(recipe.result))
  581.                 process.processed = true
  582.                 local input_c, devices = recipe.input_c, recipe.devices
  583.                 for _, proc in ipairs(crafting_status) do
  584.                     if proc.recipe and not proc.processed and proc.process_id ~= process.process_id then
  585.                         local proc_recipe = proc.recipe
  586.                         if input_c and proc_recipe.input_c == input_c and proc.status ~= 'in_progress' then
  587.                             log("Marking as 'busy' due to shared input container: " .. input_c)
  588.                             proc.status, proc.processed = "busy", true
  589.                         elseif devices then
  590.                             for dev in pairs(devices) do
  591.                                 if proc_recipe.devices and proc_recipe.devices[dev] then
  592.                                     log("Marking as 'busy' due to shared device: " .. dev)
  593.                                     proc.status, proc.processed = "busy", true
  594.                                 end
  595.                             end
  596.                         end
  597.                     end
  598.                 end
  599.             end
  600.         end
  601.     end
  602.  
  603.     -- Update 'busy' processes with their item amounts
  604.     for _, process in ipairs(crafting_status) do
  605.         if process.status == 'busy' then
  606.             local recipe = process.recipe
  607.             if recipe then
  608.                 process.amount = tostring(get_amount(recipe.result))
  609.             end
  610.         end
  611.     end
  612.  
  613.     -- Second pass: handle 'busy' recipes and dependencies
  614.     local prog_set = false
  615.     for _, process in ipairs(crafting_status) do
  616.         if process.status == 'busy' and not process.processed then
  617.             local recipe = process.recipe
  618.             if recipe then
  619.                 log("Processing 'busy' recipe: " .. pretty.pretty(recipe.result))
  620.                 if (function()
  621.                     if not recipe.multi_craft then
  622.                         if recipe.scheme then
  623.                             for _, proc in ipairs(crafting_status) do
  624.                                 if proc.recipe.scheme and proc.status == 'in_progress' and proc.recipe.input_c == recipe.input_c and proc.process_id ~= process.process_id then
  625.                                     log("Found conflicting 'in_progress' with same input container: " .. recipe.input_c)
  626.                                     return false
  627.                                 end
  628.                             end
  629.                             for _, row in ipairs(recipe.scheme) do
  630.                                 for _, item in ipairs(row) do
  631.                                     if item[1] ~= "" then
  632.                                         for _, pro in ipairs(crafting_status) do
  633.                                             if pro.recipe.result == item[1] then
  634.                                                 log("Dependency found, cannot proceed: " .. item[1])
  635.                                                 return false
  636.                                             end
  637.                                         end
  638.                                     end
  639.                                 end
  640.                             end
  641.                         else
  642.                             if count_active_crafts_for_input(recipe.input_c) >= 1 or count_active_custom_crafts_for_devices(recipe.devices) >= 1 then
  643.                                 return false
  644.                             end
  645.                         end
  646.                         return true
  647.                     else
  648.                         if process.recipe.amount == 0 then return false end
  649.                         local multi_c = recipe.multi_limit or 1
  650.                         if recipe.scheme then
  651.                             local crafts = {}
  652.                             for _, proc in ipairs(crafting_status) do
  653.                                 if proc.recipe.scheme and proc.status == 'in_progress' and proc.recipe.input_c == recipe.input_c and proc.process_id ~= process.process_id then
  654.                                     table.insert(crafts, proc)
  655.                                 end
  656.                             end
  657.                             if (#crafts+1) >= multi_c then
  658.                                 return false
  659.                             end
  660.                            
  661.                             for _, row in ipairs(recipe.scheme) do
  662.                                 for _, item in ipairs(row) do
  663.                                     if item[1] ~= "" then
  664.                                         for _, pro in ipairs(crafting_status) do
  665.                                             log("item")
  666.                                             log(item[1])
  667.                                             if pro.recipe.result == item[1] then
  668.                                                 log("Dependency found, cannot proceed: " .. item[1])
  669.                                                 return false
  670.                                             end
  671.                                         end
  672.                                     end
  673.                                 end
  674.                             end
  675.                             if process.recipe.amount then
  676.                                 if count_active_crafts_for_input(recipe.input_c) > 1 then
  677.                                     return false
  678.                                 end
  679.                                 for _, proc in ipairs(crafting_status) do
  680.                                     if process.status == 'in_progress' or proc.status == 'in_progress' then
  681.                                         if process.process_id ~= proc.process_id then
  682.                                             if proc.result == recipe.result then
  683.                                                 return false
  684.                                             end
  685.                                             if proc.input_c == process.input_c then
  686.                                                 return false
  687.                                             end
  688.                                         end
  689.                                     end
  690.                                 end
  691.                             end
  692.                         elseif recipe.devices then
  693.                             if count_active_custom_crafts_for_devices(recipe.devices) >= multi_c then
  694.                                 return false
  695.                             end
  696.                             if process.recipe.amount then
  697.                                 if count_active_crafts_for_input(recipe.input_c) > 1 then
  698.                                     return false
  699.                                 end
  700.                                 for _, proc in ipairs(crafting_status) do
  701.                                     if process.status == 'in_progress' or proc.status == 'in_progress' then
  702.                                         if process.process_id ~= proc.process_id then
  703.                                             if proc.result == recipe.result then
  704.                                                 return false
  705.                                             end
  706.                                             if proc.input_c == process.input_c then
  707.                                                 return false
  708.                                             end
  709.                                         end
  710.                                     end
  711.                                 end
  712.                             end
  713.                         end
  714.                         if (process.recipe.amount == 1 or process.recipe.amount == nil) then
  715.                             local numeric_merge = 1
  716.                             for _, proc in ipairs(crafting_status) do
  717.                                 if  table.concat(proc.recipe) == table.concat(process.recipe) and process.process_id ~= proc.process_id and numeric_merge <= multi_c and (proc.recipe.amount == 1 or proc.recipe.amount == nil) then
  718.                                     numeric_merge = numeric_merge + 1
  719.                                     proc.recipe.amount = 0
  720.                                 end
  721.                             end
  722.                             process.recipe.amount = numeric_merge
  723.                             updateCountKeys(process.recipe, numeric_merge)
  724.                         end
  725.                         return true
  726.                     end
  727.                 end)() then
  728.                     if not prog_set then
  729.                         prog_set = true
  730.                         process.status = 'in_progress'
  731.                         log("Starting crafting process for: " .. pretty.pretty(recipe.result))
  732.                         if do_craft(recipe) == '' then
  733.                             log("Crafting Error : " .. recipe.result)
  734.                             process.status = ''
  735.                         end
  736.                         process.processed = true
  737.                     end
  738.                 end
  739.             end
  740.         end
  741.     end
  742.  
  743.     -- Process output containers and update statuses
  744.     for _, process in ipairs(crafting_status) do
  745.         local recipe = process.recipe
  746.         if recipe and recipe.devices then
  747.             for dev, slots in pairs(recipe.devices) do
  748.                 for slot, data in pairs(slots) do
  749.                     if data[1] == "output" then
  750.                         items:insert(dev, tonumber(slot), 64)
  751.                     end
  752.                 end
  753.             end
  754.         elseif recipe and recipe.output_c then
  755.             for slot, _ in pairs(peripheral.call(recipe.output_c, "list") or {}) do
  756.                 items:insert(recipe.output_c, tonumber(slot), 64)
  757.             end
  758.         end
  759.     end
  760.  
  761.     -- Final pass: mark completed processes and retry busy or in-progress items
  762.     for _, process in ipairs(crafting_status) do
  763.         local recipe = process.recipe
  764.         if recipe then
  765.             if have_enough_simp(recipe.result, recipe.count + tonumber(process.amount or 0)) and process.status == 'in_progress' then
  766.                 process.status = "completed"
  767.                 log("crafting for item " .. recipe.result .. " done")
  768.             elseif process.status == "busy" or process.status == "in_progress" then
  769.                 if process.recipe.amount ~= 0 then
  770.                     table.insert(updated_status, process)
  771.                 end
  772.             end
  773.         end
  774.     end
  775.  
  776.     -- Save and reset
  777.     save_crafting_status(updated_status)
  778.     for _, process in ipairs(crafting_status) do
  779.         process.processed = nil
  780.     end
  781.     check_done = true
  782. end
  783. function try_multi_craft(recipe,coun)
  784.     local recipes = load_recipes()
  785.     local recipe_found = recipes.crafting[recipe] or recipes.custom[recipe]
  786.     if not recipe_found then not_enough(recipe,count) inserting = false return end
  787.     count = coun
  788.     if not recipe_found.multi_craft or recipe_found.multi_limit == 1 then
  789.         if recipes.crafting[recipe] then
  790.             for i = 1, count do
  791.                 craft_crafting_recipe(recipe_found,1)
  792.             end
  793.         elseif recipes.custom[recipe] then
  794.             for i = 1, count do
  795.                 craft_custom_recipe(recipe_found,1)
  796.             end
  797.         end
  798.     elseif recipe_found.multi_craft and recipe_found.multi_limit > 1 and (tonumber(coun) <= tonumber(recipe_found.multi_limit)) then
  799.         parallel.waitForAny(wait, wait)
  800.         inserting = true
  801.         updateCountKeys(recipe_found, coun)
  802.         if recipes.crafting[recipe] then
  803.             -- Main logic to gather and craft missing items
  804.             local missing_items = aggregate_missing_items(get_missing_from_scheme(recipe_found.scheme))
  805.             -- Process each unique missing item
  806.             for item_name, required_count in pairs(missing_items) do
  807.                 -- Look for a recipe for the missing item in crafting or custom recipes
  808.                 local f_recipe = recipes.crafting[item_name] or recipes.custom[item_name]
  809.                 if f_recipe then
  810.                     -- Calculate the minimum crafting runs needed based on recipe count
  811.                     local output_count = f_recipe.count
  812.                     local craft_count = math.ceil(required_count/output_count)
  813.                     -- Craft just enough to meet the requirement
  814.                     log(craft_count)
  815.                     if try_multi_craft(item_name, craft_count) == false then
  816.                         not_enough({ { item_name, required_count } })
  817.                         inserting = false
  818.                         return false
  819.                     end
  820.                 else
  821.                     -- No recipe for missing item, so crafting cannot continue
  822.                     not_enough({ { item_name, required_count } })
  823.                     inserting = false
  824.                     return false
  825.                 end
  826.             end
  827.         else
  828.             for device, inputs in pairs(recipe_found.devices) do
  829.                 for slot, input in pairs(inputs) do
  830.                     local item = input[1]
  831.                     if item ~= "output" then
  832.                         local co = input[2].count or 1
  833.                         local old = item
  834.                         if item.tags then
  835.                             item = item.tags
  836.                         end
  837.        
  838.                         -- Check if the item is available, and handle sub-recipes if it’s missing
  839.                         if not has_enough_item_or_tag(old, count) then
  840.                             local f_recipe = recipes.crafting[old] or recipes.custom[old]
  841.        
  842.                             if f_recipe then
  843.                                 -- Calculate minimum crafting runs needed based on recipe count
  844.                                 local output_count = f_recipe.count
  845.                                 local craft_count = math.ceil(co/output_count)
  846.        
  847.                                 -- Craft just enough to meet the requirement
  848.                                 if try_multi_craft(old, craft_count) == false then
  849.                                     not_enough({ { old, required_count } })
  850.                                     inserting = false
  851.                                     return false
  852.                                 end
  853.                             else
  854.                                 -- No recipe for missing item, so crafting cannot continue
  855.                                 not_enough({{old, count}})
  856.                                 inserting = false
  857.                                 return false
  858.                             end
  859.                         end
  860.                     end
  861.                 end
  862.             end
  863.         end
  864.         local crafting_status = load_crafting_status()
  865.         local process
  866.         if recipes.crafting[recipe] then
  867.             process = {
  868.                 recipe = recipe_found,
  869.                 type = "crafting",
  870.                 status = "busy",
  871.                 amount = tostring(get_amount(recipe_found.result)),
  872.             }
  873.         else
  874.             process = {
  875.                 recipe = recipe_found,
  876.                 type = "custom",
  877.                 status = "busy",
  878.                 amount = tostring(get_amount(recipe_found.result)),
  879.             }
  880.         end
  881.         process.recipe.amount = coun
  882.         table.insert(crafting_status, process)
  883.         save_crafting_status(crafting_status)
  884.         inserting = false
  885.     elseif tonumber(coun) > tonumber(recipe_found.multi_limit) then
  886.         print(coun)
  887.         try_multi_craft(recipe,recipe_found.multi_limit)
  888.         try_multi_craft(recipe,coun-recipe_found.multi_limit)
  889.         inserting = false
  890.     end
  891.     inserting = false
  892. end
  893.  
  894.  
  895.  
  896. function log(text)
  897.     --local file = io.open("log.txt", "a")  -- Open in append mode
  898.     --file:write(tostring(text) .. "\n")    -- Add a newline after each log entry
  899.     --file:close()
  900. end
  901.  
  902. return function(context)
  903.     items = context:require "artist.core.items"
  904.  
  905.     -- have_enough function
  906.     function have_enough(item_name, count)
  907.         os.sleep(0.01)
  908.         local total_count = 0 + get_count_by_name(used_items,item_name)
  909.  
  910.         for _, inventory in pairs(items.inventories) do
  911.             for _, slot in pairs(inventory.slots or {}) do
  912.                 local item = items.item_cache[slot.hash]
  913.                 if item and item.details and item.details.name and item.details.name == item_name then
  914.                     total_count = total_count + slot.count
  915.                 end
  916.             end
  917.         end
  918.  
  919.         return tonumber(total_count) >= tonumber(count)
  920.     end
  921.  
  922.     -- have_enough function
  923.     function have_enough_simp(item_name, count)
  924.         os.sleep(0.01)
  925.         local total_count = 0
  926.  
  927.         for _, inventory in pairs(items.inventories) do
  928.             for _, slot in pairs(inventory.slots or {}) do
  929.                 local item = items.item_cache[slot.hash]
  930.                 if item and item.details and item.details.name and item.details.name == item_name then
  931.                     total_count = total_count + slot.count
  932.                 end
  933.             end
  934.         end
  935.  
  936.         return total_count >= count
  937.     end
  938.  
  939.     function get_amount(item_name)
  940.         local total_count = 0
  941.  
  942.         for _, inventory in pairs(items.inventories) do
  943.             for _, slot in pairs(inventory.slots or {}) do
  944.                 local item = items.item_cache[slot.hash]
  945.                 if item and item.details and item.details.name and item.details.name == item_name then
  946.                     total_count = total_count + slot.count
  947.                 end
  948.             end
  949.         end
  950.  
  951.         return total_count
  952.     end
  953.  
  954.     -- do_craft function
  955.     function do_craft(recipe)
  956.         if recipe.scheme then
  957.             local num = 0
  958.             for _, row in ipairs(recipe.scheme) do
  959.                 for _, item in ipairs(row) do
  960.                     num = num + 1
  961.                     if item ~= "" then
  962.                         local c, use
  963.                         if type(item) == "table" then
  964.                             c = item[2].count or 1
  965.                             if type(item[1]) == "table" then
  966.                                 for _, name in ipairs(item[1].tags) do
  967.                                     if have_enough(name, c) then
  968.                                         use = name
  969.                                         break
  970.                                     end
  971.                                 end
  972.                             else
  973.                                 use = item[1]
  974.                             end
  975.                         else
  976.                             use = item
  977.                             c = 1
  978.                         end
  979.                    
  980.                         if use and have_enough(use, c) then
  981.                             local cache = nil
  982.                             for _, val in pairs(items.item_cache) do
  983.                                 if val.hash == use then
  984.                                     cache = val
  985.                                     break
  986.                                 end
  987.                             end
  988.                        
  989.                             if cache then
  990.                                 local status, result = pcall(function()
  991.                                     items:extract(recipe.input_c, cache.hash, c, num)
  992.                                 end)
  993.                                 log("!!!status")
  994.                                 log(status)
  995.                                 if not status then return '' end
  996.                             end
  997.                         end
  998.                     end
  999.                 end
  1000.             end
  1001.         elseif recipe.devices then
  1002.             for device, ins in pairs(recipe.devices) do
  1003.                 for slot, item in pairs(ins) do
  1004.                     if item[1] ~= "output" then
  1005.                         local use, c
  1006.                         if item[1].tags then
  1007.                             c = item[2].count or 1
  1008.                             for _, name in ipairs(item[1].tags) do
  1009.                                 if have_enough(name, c) then
  1010.                                     use = name
  1011.                                     break
  1012.                                 end
  1013.                             end
  1014.                         else
  1015.                             use = item[1]
  1016.                             c = item[2].count or 1
  1017.                         end
  1018.                    
  1019.                         if use and have_enough(use, c) then
  1020.                             local cache = nil
  1021.                             for _, val in pairs(items.item_cache) do
  1022.                                 if val.hash == use then
  1023.                                     cache = val
  1024.                                     break
  1025.                                 end
  1026.                             end
  1027.                        
  1028.                             if cache then
  1029.                                 items:extract(device, cache.hash, c, tonumber(slot))
  1030.                             end
  1031.                         end
  1032.                     end
  1033.                 end
  1034.             end
  1035.         end
  1036.         return "in_progress"
  1037.     end
  1038.    
  1039.     --save_crafting_status({})
  1040.     local next_reload = nil
  1041.     local function queue_reload()
  1042.         if next_reload then return end
  1043.         next_reload = os.startTimer(0.2)
  1044.     end
  1045.     local function update_dropoff_pl(item)
  1046.         local crafting_status = load_crafting_status()
  1047.         for _, process in ipairs(crafting_status) do
  1048.             if process.recipe.result == item.name then
  1049.                 process.amount = process.amount + item.count
  1050.             end
  1051.         end
  1052.         save_crafting_status(crafting_status)
  1053.     end
  1054.     local function update_dropoff_mn(item)
  1055.         local crafting_status = load_crafting_status()
  1056.         for _, process in ipairs(crafting_status) do
  1057.             if process.recipe.result == item.name then
  1058.                 process.amount = process.amount - item.count
  1059.             end
  1060.         end
  1061.         save_crafting_status(crafting_status)
  1062.     end
  1063.     function not_enough(missing_items)
  1064.         log("not enough "..pretty.pretty(missing_items))
  1065.         context.mediator:publish("crafting.missing", missing_item)
  1066.     end
  1067.     function get_crafts()
  1068.         local crafts = {}
  1069.         local resc = load_recipes()
  1070.         for craft,_ in pairs(resc["crafting"]) do
  1071.             table.insert(crafts,craft)
  1072.         end
  1073.         for craft,_ in pairs(resc["custom"]) do
  1074.             table.insert(crafts,craft)
  1075.         end
  1076.         return crafts
  1077.     end
  1078.     context.mediator:subscribe("dropoff.add", update_dropoff_pl)
  1079.     context.mediator:subscribe("pickup.take", update_dropoff_mn)
  1080.     Crafting.get_crafts = get_crafts
  1081.     Crafting.try_multi_craft = try_multi_craft
  1082.     context:spawn(function()
  1083.         while true do
  1084.             os.sleep(0.001)
  1085.             if check_done then
  1086.                 if not inserting then
  1087.                     check_crafting_status()
  1088.                 end
  1089.             end
  1090.         end
  1091.     end)
  1092.     return Crafting
  1093. end
  1094.  
  1095.  
  1096.  
  1097.  
  1098.  
  1099.  
Add Comment
Please, Sign In to add comment