summaryrefslogtreecommitdiff
path: root/autocrafter.lua
diff options
context:
space:
mode:
Diffstat (limited to 'autocrafter.lua')
-rw-r--r--autocrafter.lua131
1 files changed, 71 insertions, 60 deletions
diff --git a/autocrafter.lua b/autocrafter.lua
index 3579e8b..4216517 100644
--- a/autocrafter.lua
+++ b/autocrafter.lua
@@ -2,78 +2,85 @@ local autocrafterCache = {} -- caches some recipe data to avoid to call the slo
local function count_index(invlist)
local index = {}
- for _, stack in ipairs(invlist) do
- local stack_name = stack:get_name()
- index[stack_name] = (index[stack_name] or 0) + stack:get_count()
+ for _, stack in pairs(invlist) do
+ if not stack:is_empty() then
+ local stack_name = stack:get_name()
+ index[stack_name] = (index[stack_name] or 0) + stack:get_count()
+ end
end
return index
end
-local function get_cached_craft(pos)
- local hash = minetest.hash_node_position(pos)
- return hash, autocrafterCache[hash]
+local function get_craft(pos, inventory, hash)
+ local hash = hash or minetest.hash_node_position(pos)
+ local craft = autocrafterCache[hash]
+ if not craft then
+ if inventory:is_empty("recipe") then return nil end
+ local recipe = inventory:get_list("recipe")
+ local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
+ craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
+ autocrafterCache[hash] = craft
+
+ end
+ -- only return crafts that have an actual result
+ if not craft.output.item:is_empty() then
+ return craft
+ end
end
-- note, that this function assumes allready being updated to virtual items
-- and doesn't handle recipes with stacksizes > 1
local function on_recipe_change(pos, inventory)
- if not inventory then return end
+ -- if we emptied the grid, there's no point in keeping it running or cached
+ if inventory:is_empty("recipe") then
+ minetest.get_node_timer(pos):stop()
+ autocrafterCache[minetest.hash_node_position(pos)] = nil
+ return
+ end
+ local recipe_changed = false
local recipe = inventory:get_list("recipe")
- if not recipe then return end
- local recipe_changed = false
- local hash, craft = get_cached_craft(pos)
+ local hash = minetest.hash_node_position(pos)
+ local craft = autocrafterCache[hash]
- if not craft then
- recipe_changed = true
- else
+ if craft then
-- check if it changed
- local cached_recipe = craft.recipe
+ local cached_recipe = craft.recipe
for i = 1, 9 do
if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
- recipe_changed = true
+ autocrafterCache[hash] = nil -- invalidate recipe
+ craft = nil
break
end
end
end
- if recipe_changed then
- local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
- craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
- autocrafterCache[hash] = craft
+ local timer = minetest.get_node_timer(pos)
+ if not timer:is_started() then
+ timer:start(1)
end
-
- return craft
end
-local function update_autocrafter(pos)
- local meta = minetest.get_meta(pos)
- if meta:get_string("virtual_items") == "" then
- meta:set_string("virtual_items", "1")
- local inv = meta:get_inventory()
- for idx, stack in ipairs(inv:get_list("recipe")) do
- minetest.item_drop(stack, "", pos)
- stack:set_count(1)
- stack:set_wear(0)
- inv:set_stack("recipe", idx, stack)
- end
- on_recipe_change(pos, inv)
+local function on_inventory_change(pos, inventory)
+ local timer = minetest.get_node_timer(pos)
+ if not timer:is_started() then
+ timer:start(1)
end
end
local function autocraft(inventory, craft)
+ if not craft then return false end
local output_item = craft.output.item
+
-- check if we have enough room in dst
if not inventory:room_for_item("dst", output_item) then return false end
-
local consumption = craft.consumption
local inv_index = count_index(inventory:get_list("src"))
- -- check if we have enough materials available
+ -- check if we have enough material available
for itemname, number in pairs(consumption) do
if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
end
-
- -- consume materials
+ -- consume material
for itemname, number in pairs(consumption) do
for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
inventory:remove_item("src", ItemStack(itemname))
@@ -88,22 +95,28 @@ local function autocraft(inventory, craft)
return true
end
-local function run_autocrafter(inventory, pos)
- if not inventory then return end
- local recipe = inventory:get_list("recipe")
- if not recipe then return end
+-- returns false to stop the timer, true to continue running
+-- is started only from start_autocrafter(pos) after sanity checks and cached recipe
+local function run_autocrafter(pos, elapsed)
+ local meta = minetest.get_meta(pos)
+ local inventory = meta:get_inventory()
+ local craft = get_craft(pos, inventory)
+ return autocraft(inventory, craft)
+end
- local _, craft = get_cached_craft(pos)
- if craft == nil then
- update_autocrafter(pos) -- only does some unnecessary calls for "old" autocrafters
- craft = on_recipe_change(pos, inventory)
+local function update_autocrafter(pos)
+ local meta = minetest.get_meta(pos)
+ if meta:get_string("virtual_items") == "" then
+ meta:set_string("virtual_items", "1")
+ local inv = meta:get_inventory()
+ for idx, stack in ipairs(inv:get_list("recipe")) do
+ minetest.item_drop(stack, "", pos)
+ stack:set_count(1)
+ stack:set_wear(0)
+ inv:set_stack("recipe", idx, stack)
+ end
+ on_recipe_change(pos, inv)
end
-
- -- skip crafts that have no output
- local output_item = craft.output.item
- if output_item:is_empty() then return end
-
- autocraft(inventory, craft)
end
minetest.register_node("pipeworks:autocrafter", {
@@ -114,7 +127,9 @@ minetest.register_node("pipeworks:autocrafter", {
tube = {insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
- return inv:add_item("src", stack)
+ local added = inv:add_item("src", stack)
+ on_inventory_change(pos, inv)
+ return added
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
@@ -162,6 +177,7 @@ minetest.register_node("pipeworks:autocrafter", {
on_recipe_change(pos, inv)
return 0
else
+ on_inventory_change(pos, inv)
return stack:get_count()
end
end,
@@ -173,6 +189,7 @@ minetest.register_node("pipeworks:autocrafter", {
on_recipe_change(pos, inv)
return 0
else
+ on_inventory_change(pos, inv)
return stack:get_count()
end
end,
@@ -192,15 +209,9 @@ minetest.register_node("pipeworks:autocrafter", {
on_recipe_change(pos, inv)
return 0
else
+ on_inventory_change(pos, inv)
return stack:get_count()
end
end,
-})
-
-minetest.register_abm({nodenames = {"pipeworks:autocrafter"}, interval = 1, chance = 1,
- action = function(pos, node)
- local meta = minetest.get_meta(pos)
- local inv = meta:get_inventory()
- run_autocrafter(inv, pos)
- end
+ on_timer = run_autocrafter
})