feat: implement auto-crafting feature for excess stock management

This commit is contained in:
MayaTheShy
2026-03-25 18:07:26 -04:00
parent 2c99169ce9
commit f327f82677
6 changed files with 99 additions and 0 deletions

14
data/auto_craft.lua Normal file
View File

@@ -0,0 +1,14 @@
-- Auto-craft rules: items that should be automatically crafted when stock exceeds reserve.
-- The system will keep `reserve` of the input item and craft all excess into the output.
-- Requires a crafting turtle to be connected.
--
-- Format: { input = "mod:item", reserve = N, output = "mod:output_item" }
-- The output item must have a recipe in data/craftable.lua (or learned via recipeBook).
-- Recursive crafting is used, so intermediate steps are handled automatically.
return {
-- Convert excess bamboo into planks (keeps 128 raw bamboo as reserve)
{ input = "minecraft:bamboo", reserve = 128, output = "minecraft:bamboo_planks" },
-- Convert excess bamboo blocks into planks too (keeps 64 blocks as reserve)
{ input = "minecraft:bamboo_block", reserve = 64, output = "minecraft:bamboo_planks" },
}

View File

@@ -443,6 +443,25 @@ local function main()
end
end,
-- Task 5c: Auto-craft excess items into target products
function()
if #cfg.AUTO_CRAFT_RULES == 0 then
while true do sleep(3600) end
end
sleep(12) -- let initial scan + discard settle first
log.info("AUTOCRAFT", "Auto-craft active with %d rule(s)", #cfg.AUTO_CRAFT_RULES)
while true do
if ctx.craftTurtleName then
activity.autocrafting = true
state.needsRedraw = true
pcall(ops.autoCraft)
activity.autocrafting = false
state.needsRedraw = true
end
sleep(cfg.AUTO_CRAFT_INTERVAL)
end
end,
-- Task 6: Low-stock alert checker
function()
sleep(5)

View File

@@ -64,6 +64,9 @@ C.TRASH_DROPPERS = { -- droppers facing lava/void for destroying
}
C.DISCARD_INTERVAL = 5 -- seconds between discard checks
-- Auto-craft (overridable via config file)
C.AUTO_CRAFT_INTERVAL = 10 -- seconds between auto-craft checks
-- Peripheral
C.PERIPHERAL_CACHE_TTL = 5
@@ -126,6 +129,7 @@ function C.loadConfig()
if cfg.compostHopper then C.COMPOST_HOPPER = cfg.compostHopper end
if cfg.trashDroppers then C.TRASH_DROPPERS = cfg.trashDroppers end
if cfg.discardInterval then C.DISCARD_INTERVAL = cfg.discardInterval end
if cfg.autoCraftInterval then C.AUTO_CRAFT_INTERVAL = cfg.autoCraftInterval end
if cfg.stockLimits then
for item, limit in pairs(cfg.stockLimits) do
C.STOCK_LIMITS[item] = limit -- merge / override per-item
@@ -149,6 +153,7 @@ local _compostData = dofile(_path("data/compostable.lua"))
C.COMPOSTABLE = _compostData.items
C.COMPOST_TRASH = _compostData.trash
C.STOCK_LIMITS = dofile(_path("data/stock_limits.lua"))
C.AUTO_CRAFT_RULES = dofile(_path("data/auto_craft.lua"))
C.LOW_STOCK_ALERTS = dofile(_path("data/alerts.lua"))
-- Recipe book: merges built-in recipes + user-learned recipes

View File

@@ -80,6 +80,7 @@ local function getActivityString()
if activity.defragging then table.insert(parts, "DEFRAG") end
if activity.composting then table.insert(parts, "COMPOST") end
if activity.discarding then table.insert(parts, "DISCARD") end
if activity.autocrafting then table.insert(parts, "AUTOCRAFT") end
if #parts > 0 then
return table.concat(parts, " | ")
end
@@ -93,6 +94,7 @@ local function getBottomMessage()
elseif activity.defragging then return "DEFRAGMENTING..."
elseif activity.composting then return "COMPOSTING..."
elseif activity.discarding then return "DISCARDING EXCESS..."
elseif activity.autocrafting then return "AUTO-CRAFTING..."
end
return "Tap item to order"
end

View File

@@ -851,6 +851,64 @@ function O.discardExcess()
return didWork
end
-------------------------------------------------
-- Auto-craft excess stock into target items
-------------------------------------------------
function O.autoCraft()
if #cfg.AUTO_CRAFT_RULES == 0 then return false end
if not ctx.craftEngine then return false end
if not ctx.craftTurtleName then return false end
local catalogue = cache.catalogue
local didWork = false
for _, rule in ipairs(cfg.AUTO_CRAFT_RULES) do
local inputName = rule.input
local reserve = rule.reserve or 0
local outputName = rule.output
if catalogue[inputName] then
local totalInStorage = 0
for _, src in ipairs(catalogue[inputName]) do
totalInStorage = totalInStorage + src.total
end
local excess = totalInStorage - reserve
if excess > 0 then
-- Figure out how many input items per craft batch
local recipe = cfg.recipeBook.getCraftingRecipe(outputName)
if recipe then
local ingredients = cfg.recipeBook.getIngredients(recipe)
local inputPerCraft = ingredients[inputName] or 0
if inputPerCraft > 0 then
-- How many batches can we do with the excess?
local batches = math.floor(excess / inputPerCraft)
-- Limit to a reasonable amount per cycle to avoid blocking
batches = math.min(batches, 64)
if batches > 0 then
local craftCount = batches * recipe.count
log.info("AUTOCRAFT", "%s: %d excess (reserve %d), crafting %d x %s",
inputName, excess, reserve, craftCount, outputName)
local ok, err = O.recursiveCraft(outputName, craftCount)
if ok then
didWork = true
log.info("AUTOCRAFT", "Crafted %s x%d", outputName, craftCount)
else
log.warn("AUTOCRAFT", "Failed to craft %s: %s", outputName, tostring(err))
end
end
end
else
log.warn("AUTOCRAFT", "No recipe found for output: %s", outputName)
end
end
end
end
return didWork
end
-------------------------------------------------
-- Low-stock alert checker
-------------------------------------------------

View File

@@ -42,6 +42,7 @@ S.activity = {
composting = false,
crafting = false,
discarding = false,
autocrafting = false,
}
-------------------------------------------------