From 46c95f31427da975de49a6f489b9224c4f06ec10 Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Fri, 20 Feb 2026 14:00:44 +0100 Subject: [PATCH 1/6] add function Added a button, on to select whether to keep 1 item in the ingredient slot and prevent other ingredients from filling it, off to completely empty the slots when crafting --- autocrafter.lua | 71 +++++++++++++++++++++++++++-------- locale/pipeworks.it.tr | 85 ++++++++++++++++++++++++++++++++++++++++++ locale/template.txt | 6 ++- 3 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 locale/pipeworks.it.tr diff --git a/autocrafter.lua b/autocrafter.lua index deeca6d6..442f1748 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -207,7 +207,7 @@ local function has_room_for_output(list_output, index_output) return true end -local function autocraft(inventory, craft) +local function autocraft(inventory, craft,pos) if not craft then return false end -- check if output and all replacements fit in dst @@ -223,9 +223,17 @@ local function autocraft(inventory, craft) -- check if we have enough material available local inv_index = count_index(inventory:get_list("src")) local consumption = calculate_consumption(inv_index, craft.consumption) + if not consumption then return false end + -- BLOCk (Riserve 1 item) + if core.get_meta(pos):get_int("reserve") == 1 then + for item, num in pairs(consumption) do + if (inv_index[item] or 0) <= num then return false end + end + end + -- consume material for itemname, number in pairs(consumption) do @@ -263,7 +271,7 @@ local function run_autocrafter(pos, elapsed) end for _ = 1, math.floor(elapsed / craft_time) do - local continue = autocraft(inventory, craft) + local continue = autocraft(inventory, craft,pos) if not continue then return false end end return true @@ -344,10 +352,17 @@ local function on_output_change(pos, inventory, stack) end -- returns false if we shouldn't bother attempting to start the timer again --- after this + local function update_meta(meta, enabled) local state = enabled and "on" or "off" meta:set_int("enabled", enabled and 1 or 0) + + -- Reserve State + local res_state = meta:get_int("reserve") == 1 + local res_icon = res_state and "pipeworks_button_on.png" or "pipeworks_button_off.png" + local res_status_txt = res_state and S("RESERVE: ON") or S("RESERVE: OFF") + local res_tooltip = res_status_txt .. "\n" .. S("Keep 1 item in slot to prevent other items from filling it.") + local list_backgrounds = "" if core.get_modpath("i3") or core.get_modpath("mcl_formspec") then list_backgrounds = "style_type[box;colors=#666]" @@ -370,6 +385,7 @@ local function update_meta(meta, enabled) end end end + local size = "10.2,14" local fs = "formspec_version[2]" .. @@ -379,8 +395,11 @@ local function update_meta(meta, enabled) "list[context;recipe;0.22,0.22;3,3;]" .. "image[4,1.45;1,1;[combine:16x16^[noalpha^[colorize:#141318:255]" .. "list[context;output;4,1.45;1,1;]" .. - "image_button[4,2.6;1,0.6;pipeworks_button_" .. state .. ".png;" .. - state .. ";;;false;pipeworks_button_interm.png]" .. + "image_button[4.1,2.6;0.8,0.5;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" .. + "image_button[4.1,3.1;0.8,0.5;" .. res_icon .. ";btn_reserve;;;false;pipeworks_button_interm.png]" .. + "style[label_res;font_size=12]" .. + "label[3.6,3.95;" .. res_status_txt .. "]" .. + "tooltip[btn_reserve;" .. res_tooltip .. "]" .. "list[context;dst;5.28,0.22;4,3;]" .. "list[context;src;0.22,5;8,3;]" .. pipeworks.fs_helpers.get_inv(9) .. @@ -389,24 +408,22 @@ local function update_meta(meta, enabled) "listring[current_player;main]" .. "listring[context;dst]" .. "listring[current_player;main]" + if core.get_modpath("digilines") then - fs = fs .. "field[0.22,4.1;4.5,0.75;channel;" .. S("Channel") .. - ";${channel}]" .. - "button[5,4.1;2,0.75;set_channel;" .. S("Set") .. "]" .. - "button_exit[7.2,4.1;2,0.75;close;" .. S("Close") .. "]" + + fs = fs .. "field[0.22,4.1;4.0,0.5;channel;" .. S("Channel") .. ";${channel}]" .. + "button[4.5,4.1;1.2,0.5;set_channel;" .. S("Set") .. "]" .. + "button_exit[6.0,4.1;1.5,0.5;close;" .. S("Close") .. "]" end meta:set_string("formspec", fs) - -- toggling the button doesn't quite call for running a recipe change check - -- so instead we run a minimal version for infotext setting only - -- this might be more written code, but actually executes less - local output = meta:get_inventory():get_stack("output", 1) - if output:is_empty() then -- doesn't matter if paused or not + local output_stack = meta:get_inventory():get_stack("output", 1) + if output_stack:is_empty() then meta:set_string("infotext", S("unconfigured Autocrafter")) return false end - local description, name = get_item_info(output) + local description, name = get_item_info(output_stack) local infotext = enabled and S("'@1' Autocrafter (@2)", description, name) or S("paused '@1' Autocrafter", description) @@ -414,6 +431,14 @@ local function update_meta(meta, enabled) return enabled end + + + + + + + + -- 1st version of the autocrafter had actual items in the crafting grid -- the 2nd replaced these with virtual items, dropped the content on update and -- set "virtual_items" to string "1" @@ -484,6 +509,8 @@ core.register_node("pipeworks:autocrafter", { inv:set_size("recipe", 3 * 3) inv:set_size("dst", 4 * 3) inv:set_size("output", 1) + meta:set_int("reserve", 0) + update_meta(meta, false) end, on_receive_fields = function(pos, formname, fields, sender) @@ -493,6 +520,8 @@ core.register_node("pipeworks:autocrafter", { return end local meta = core.get_meta(pos) + + -- Machine on/off management if fields.on then update_meta(meta, false) core.get_node_timer(pos):stop() @@ -501,10 +530,22 @@ core.register_node("pipeworks:autocrafter", { start_crafter(pos) end end + + -- Channel Management (if present) if fields.channel then meta:set_string("channel", fields.channel) end + + --new: Gestion Button Reserve + if fields.btn_reserve then + local current_res = meta:get_int("reserve") + local new_res = (current_res == 1 and 0 or 1) + meta:set_int("reserve", new_res) + -- Aggiorna l'interfaccia per mostrare il cambio colore + update_meta(meta, meta:get_int("enabled") == 1) + end end, + can_dig = function(pos, player) upgrade_autocrafter(pos) local meta = core.get_meta(pos) diff --git a/locale/pipeworks.it.tr b/locale/pipeworks.it.tr new file mode 100644 index 00000000..44b22930 --- /dev/null +++ b/locale/pipeworks.it.tr @@ -0,0 +1,85 @@ +# textdomain: pipeworks + +## generic interaction +Set=Imposta +Cancel=Annulla + +## digilines interfacing +Channel=Canale + +## init +Allow splitting incoming stacks from tubes=Permetti di dividere gli stack in entrata dai tubi + +## autocrafter +Unknown item=Oggetto sconosciuto +unconfigured Autocrafter: unknown recipe=Autocrafter non configurato: ricetta sconosciuta +unconfigured Autocrafter=Autocrafter non configurato +'@1' Autocrafter (@2)=Autocrafter di '@1' (@2) +Save=Salva +paused '@1' Autocrafter=Autocrafter di '@1' in pausa +Autocrafter=Autocrafter +# NUOVE TRADUZIONI PER LA RISERVA: +RESERVE: ON=RISERVA: ON +RESERVE: OFF=RISERVA: OFF +Keep 1 item in slot to prevent other items from filling it.=Mantieni 1 pezzo nello slot per evitare che altri oggetti lo riempiano. + +## devices +Pump/Intake Module=Modulo Pompa/Aspirazione +Valve=Valvola +Decorative grating=Grata decorativa +Spigot outlet=Rubinetto di scarico +Airtight Pipe entry/exit=Ingresso/Uscita tubo ermetico +Flow Sensor=Sensore di flusso +Flow sensor (on)=Sensore di flusso (acceso) +empty=vuoto +@1% full=@1% pieno +Expansion Tank (@1)=Serbatoio di espansione (@1) +Fluid Storage Tank (@1)=Serbatoio di stoccaggio liquidi (@1) +Fountainhead=Sorgente a fontana +Straight-only Pipe=Tubo solo dritto + +## filter-injector +(slot #@1 next)=(slot #@1 successivo) +@1 Filter-Injector=Iniettore-Filtro @1 +Sequence slots by Priority=Sequenza slot per priorità +Sequence slots Randomly=Sequenza slot casuale +Sequence slots by Rotation=Sequenza slot per rotazione +Exact match - off=Corrispondenza esatta - OFF +Exact match - on=Corrispondenza esatta - ON +Prefer item types:=Preferisci tipi di oggetto: +Itemwise=Per oggetto +Stackwise=Per stack +Digiline=Digiline + +## routing tubes +Pneumatic tube segment=Segmento di tubo pneumatico +Broken Tube=Tubo rotto +High Priority Tube Segment=Segmento di tubo ad alta priorità +Accelerating Pneumatic Tube Segment=Segmento di tubo pneumatico acceleratore +Crossing Pneumatic Tube Segment=Segmento di tubo pneumatico a incrocio +One way tube=Tubo a senso unico + +## sorting tubes +Sorting Pneumatic Tube Segment=Segmento di tubo pneumatico di smistamento +Sorting pneumatic tube=Tubo pneumatico di smistamento + +## teleport tube +Receive=Ricevi +Channels are public by default=I canali sono pubblici per impostazione predefinita +Use : for fully private channels=Usa : per canali privati +Teleporting Pneumatic Tube Segment=Segmento di tubo pneumatico di teletrasporto +Teleporting Tube=Tubo di teletrasporto +Unconfigured Teleportation Tube=Tubo di teletrasporto non configurato + +## trashcan +Trash Can=Cestino dei rifiuti + +## vacuum tubes +Radius=Raggio +Vacuuming Pneumatic Tube Segment=Segmento di tubo pneumatico aspirante +Adjustable Vacuuming Tube=Tubo aspirante regolabile + +## wielder +Node Breaker=Rompiblocco +Deployer=Posizionatore +Dispenser=Dispenser diff --git a/locale/template.txt b/locale/template.txt index b9c5293f..f891513d 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -21,6 +21,11 @@ unconfigured Autocrafter= Save= paused '@1' Autocrafter= Autocrafter= +# Reserve button: +RESERVE: ON= +RESERVE: OFF= + +Keep 1 item in slot to prevent other items from filling it.= ## compat-furnaces Allow splitting incoming material (not fuel) stacks from tubes= @@ -64,7 +69,6 @@ Auto-Tap= Pipe Segment= Pipe Segment (legacy)= - ## routing tubes Pneumatic tube segment= Broken Tube= From a08c5e20ec36af90ae2265d6045c2d0333da1215 Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Mon, 23 Feb 2026 01:07:30 +0100 Subject: [PATCH 2/6] Correction Code fixes and removal of non-stackable items from the reserve function --- autocrafter.lua | 37 +++++++++++++++++-------------------- locale/pipeworks.it.tr | 5 +++-- locale/template.txt | 4 ++-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/autocrafter.lua b/autocrafter.lua index 442f1748..f73304b8 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -223,18 +223,25 @@ local function autocraft(inventory, craft,pos) -- check if we have enough material available local inv_index = count_index(inventory:get_list("src")) local consumption = calculate_consumption(inv_index, craft.consumption) - if not consumption then return false end - -- BLOCk (Riserve 1 item) - if core.get_meta(pos):get_int("reserve") == 1 then - for item, num in pairs(consumption) do - if (inv_index[item] or 0) <= num then return false end + + --Excludes buckets and non-stackable items + local meta = core.get_meta(pos) + if meta:get_int("reserve") == 1 then + for itemname, number in pairs(consumption) do + local def = core.registered_items[itemname] + local stack_max = def and def.stack_max or 1 + --If it is a bucket or a non-stackable iterm , we ignore it and use it normally + if stack_max > 1 then + if (inv_index[itemname] or 0) <= number then + return false + end + end end end - -- consume material for itemname, number in pairs(consumption) do -- We have to do that since remove_item does not work if count > stack_max @@ -360,7 +367,7 @@ local function update_meta(meta, enabled) -- Reserve State local res_state = meta:get_int("reserve") == 1 local res_icon = res_state and "pipeworks_button_on.png" or "pipeworks_button_off.png" - local res_status_txt = res_state and S("RESERVE: ON") or S("RESERVE: OFF") + local res_status_txt = res_state and S("Reserve: ON") or S("Reserve: OFF") local res_tooltip = res_status_txt .. "\n" .. S("Keep 1 item in slot to prevent other items from filling it.") local list_backgrounds = "" @@ -422,7 +429,6 @@ local function update_meta(meta, enabled) meta:set_string("infotext", S("unconfigured Autocrafter")) return false end - local description, name = get_item_info(output_stack) local infotext = enabled and S("'@1' Autocrafter (@2)", description, name) or S("paused '@1' Autocrafter", description) @@ -431,14 +437,6 @@ local function update_meta(meta, enabled) return enabled end - - - - - - - - -- 1st version of the autocrafter had actual items in the crafting grid -- the 2nd replaced these with virtual items, dropped the content on update and -- set "virtual_items" to string "1" @@ -509,8 +507,7 @@ core.register_node("pipeworks:autocrafter", { inv:set_size("recipe", 3 * 3) inv:set_size("dst", 4 * 3) inv:set_size("output", 1) - meta:set_int("reserve", 0) - + meta:set_int("reserve", 0) update_meta(meta, false) end, on_receive_fields = function(pos, formname, fields, sender) @@ -536,12 +533,12 @@ core.register_node("pipeworks:autocrafter", { meta:set_string("channel", fields.channel) end - --new: Gestion Button Reserve + -- Reserve button management if fields.btn_reserve then local current_res = meta:get_int("reserve") local new_res = (current_res == 1 and 0 or 1) meta:set_int("reserve", new_res) - -- Aggiorna l'interfaccia per mostrare il cambio colore + -- Update the interface to show color change update_meta(meta, meta:get_int("enabled") == 1) end end, diff --git a/locale/pipeworks.it.tr b/locale/pipeworks.it.tr index 44b22930..07c67f62 100644 --- a/locale/pipeworks.it.tr +++ b/locale/pipeworks.it.tr @@ -18,9 +18,10 @@ unconfigured Autocrafter=Autocrafter non configurato Save=Salva paused '@1' Autocrafter=Autocrafter di '@1' in pausa Autocrafter=Autocrafter + # NUOVE TRADUZIONI PER LA RISERVA: -RESERVE: ON=RISERVA: ON -RESERVE: OFF=RISERVA: OFF +Reserve: ON=Riserva: ON +Reserve: OFF=Riserva: OFF Keep 1 item in slot to prevent other items from filling it.=Mantieni 1 pezzo nello slot per evitare che altri oggetti lo riempiano. ## devices diff --git a/locale/template.txt b/locale/template.txt index f891513d..c03b8254 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -22,8 +22,8 @@ Save= paused '@1' Autocrafter= Autocrafter= # Reserve button: -RESERVE: ON= -RESERVE: OFF= +Reserve: ON= +Reserve: OFF= Keep 1 item in slot to prevent other items from filling it.= From 922749c43aaf7ec7d8ab553317e6ef1ca9064a2a Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Mon, 23 Feb 2026 02:28:50 +0100 Subject: [PATCH 3/6] group consuption no reservation for a single element in the group but only one of them belonging to the group --- autocrafter.lua | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/autocrafter.lua b/autocrafter.lua index f73304b8..2a6633d2 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -207,58 +207,57 @@ local function has_room_for_output(list_output, index_output) return true end -local function autocraft(inventory, craft,pos) +local function autocraft(inventory, craft, pos) if not craft then return false end - -- check if output and all replacements fit in dst local output = craft.output.item local out_items = count_index(craft.decremented_input) - out_items[output:get_name()] = - (out_items[output:get_name()] or 0) + output:get_count() + out_items[output:get_name()] = (out_items[output:get_name()] or 0) + output:get_count() if not has_room_for_output(inventory:get_list("dst"), out_items) then return false end - - -- check if we have enough material available - local inv_index = count_index(inventory:get_list("src")) + local inv_list = inventory:get_list("src") + local inv_index = count_index(inv_list) local consumption = calculate_consumption(inv_index, craft.consumption) + if not consumption then return false end - --Excludes buckets and non-stackable items + --LOGIC OF THE ADDED RESERVE local meta = core.get_meta(pos) if meta:get_int("reserve") == 1 then + local total_in_inv = 0 + local total_needed = 0 + for itemname, number in pairs(consumption) do local def = core.registered_items[itemname] local stack_max = def and def.stack_max or 1 - --If it is a bucket or a non-stackable iterm , we ignore it and use it normally + + --If the object is stackable if stack_max > 1 then - if (inv_index[itemname] or 0) <= number then - return false - end + total_needed = total_needed + number + total_in_inv = total_in_inv + (inv_index[itemname] or 0) end end + + --If the total does not exceed the required total by at least 1, we stop. + if total_needed > 0 and total_in_inv <= total_needed then + return false + end end - -- consume material + --Consumption of objects for itemname, number in pairs(consumption) do - -- We have to do that since remove_item does not work if count > stack_max for _ = 1, number do inventory:remove_item("src", ItemStack(itemname)) end end - -- craft the result into the dst inventory and add any "replacements" as well inventory:add_item("dst", output) - local leftover for i = 1, 9 do - leftover = inventory:add_item("dst", craft.decremented_input[i]) - if leftover and not leftover:is_empty() then - core.log("warning", "[pipeworks] autocrafter didn't " .. - "calculate output space correctly.") - end + inventory:add_item("dst", craft.decremented_input[i]) end return true end From 4f6024d61291e3169d9d5ff10bab9da4804807be Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Mon, 23 Feb 2026 08:27:13 +0100 Subject: [PATCH 4/6] Update autocrafter.lua --- autocrafter.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/autocrafter.lua b/autocrafter.lua index 2a6633d2..14d2bc0b 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -431,11 +431,9 @@ local function update_meta(meta, enabled) local description, name = get_item_info(output_stack) local infotext = enabled and S("'@1' Autocrafter (@2)", description, name) or S("paused '@1' Autocrafter", description) - meta:set_string("infotext", infotext) return enabled end - -- 1st version of the autocrafter had actual items in the crafting grid -- the 2nd replaced these with virtual items, dropped the content on update and -- set "virtual_items" to string "1" From 7c1db3392acdcfd43270a3b5c3cfcdf95a213627 Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Sun, 1 Mar 2026 11:41:14 +0100 Subject: [PATCH 5/6] Update autocrafter.lua --- autocrafter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autocrafter.lua b/autocrafter.lua index 14d2bc0b..7ee7195a 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -277,7 +277,7 @@ local function run_autocrafter(pos, elapsed) end for _ = 1, math.floor(elapsed / craft_time) do - local continue = autocraft(inventory, craft,pos) + local continue = autocraft(inventory, craft, pos) if not continue then return false end end return true From 3ba96c6c9fbf01d75305cfe8c55e70859fe3bd14 Mon Sep 17 00:00:00 2001 From: IIIullaIII Date: Sun, 1 Mar 2026 12:42:11 +0100 Subject: [PATCH 6/6] comment -- removed First capital letter in comment and -COMMENT ALL CAPS --- autocrafter.lua | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/autocrafter.lua b/autocrafter.lua index 7ee7195a..c9dd3bfc 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -25,8 +25,8 @@ local function get_item_info(stack) return description, name end --- Get best matching recipe for what user has put in crafting grid. --- This function does not consider crafting method (mix vs craft) +-- get best matching recipe for what user has put in crafting grid. +-- this function does not consider crafting method (mix vs craft) local function get_matching_craft(output_name, example_recipe) local recipes = core.get_all_craft_recipes(output_name) if not recipes then @@ -92,7 +92,7 @@ local function get_craft(pos, inventory, hash) return craft end --- From a consumption table with groups and an inventory index, +-- from a consumption table with groups and an inventory index, -- build a consumption table without groups local function calculate_consumption(inv_index, consumption_with_groups) inv_index = table.copy(inv_index) @@ -103,8 +103,8 @@ local function calculate_consumption(inv_index, consumption_with_groups) -- table of ingredients defined as one or more groups each local grouped_ingredients = {} - -- First consume all non-group requirements - -- This is done to avoid consuming a non-group item which + -- first consume all non-group requirements + -- this is done to avoid consuming a non-group item which -- is also in a group for key, count in pairs(consumption_with_groups) do if key:sub(1, 6) == "group:" then @@ -141,15 +141,15 @@ local function calculate_consumption(inv_index, consumption_with_groups) return found == count_ingredient_groups end - -- Next, resolve groups using the remaining items in the inventory + -- next, resolve groups using the remaining items in the inventory if next(grouped_ingredients) ~= nil then local take for itemname, count in pairs(inv_index) do if count > 0 then -- groupname is the string as defined by recipe. - -- e.g. group:dye,color_blue + -- e.g. group:dye,color_blue -- groups holds the group names split into a list - -- ready to be passed to core.get_item_group() + -- ready to be passed to core.get_item_group() for groupname, groups in pairs(grouped_ingredients) do if consumption_with_groups[groupname] > 0 and ingredient_groups_match_item(groups, itemname) @@ -172,7 +172,7 @@ local function calculate_consumption(inv_index, consumption_with_groups) end end - -- Finally, check everything has been consumed + -- finally, check everything has been consumed for key, count in pairs(consumption_with_groups) do if count > 0 then return nil @@ -224,8 +224,8 @@ local function autocraft(inventory, craft, pos) if not consumption then return false end - --Excludes buckets and non-stackable items - --LOGIC OF THE ADDED RESERVE + -- ixcludes buckets and non-stackable items + -- logic of the added reserve local meta = core.get_meta(pos) if meta:get_int("reserve") == 1 then local total_in_inv = 0 @@ -235,20 +235,20 @@ local function autocraft(inventory, craft, pos) local def = core.registered_items[itemname] local stack_max = def and def.stack_max or 1 - --If the object is stackable + -- if the object is stackable if stack_max > 1 then total_needed = total_needed + number total_in_inv = total_in_inv + (inv_index[itemname] or 0) end end - --If the total does not exceed the required total by at least 1, we stop. + -- if the total does not exceed the required total by at least 1, we stop. if total_needed > 0 and total_in_inv <= total_needed then return false end end - --Consumption of objects + -- consumption of objects for itemname, number in pairs(consumption) do for _ = 1, number do inventory:remove_item("src", ItemStack(itemname)) @@ -440,7 +440,7 @@ end -- the third added an output inventory, changed the formspec and added a button -- for enabling/disabling -- so we work out way backwards on this history and update each single case --- to the newest version +-- to the newest version local function upgrade_autocrafter(pos, meta) local meta = meta or core.get_meta(pos) local inv = meta:get_inventory()