summaryrefslogtreecommitdiff
path: root/autocrafter.lua
diff options
context:
space:
mode:
authorTim <t4im@users.noreply.github.com>2015-01-27 03:45:38 +0100
committerTim <t4im@users.noreply.github.com>2015-01-27 23:41:46 +0100
commit44bafb844ac2497cab683f8a27c9c673f3a0b437 (patch)
tree8c6abccbaeb450d2e9f71b5056b50f98ffd89e6a /autocrafter.lua
parent2ccce52976a9c11313486ef3602c002b757f0dbe (diff)
downloadpipeworks-44bafb844ac2497cab683f8a27c9c673f3a0b437.tar
pipeworks-44bafb844ac2497cab683f8a27c9c673f3a0b437.tar.gz
pipeworks-44bafb844ac2497cab683f8a27c9c673f3a0b437.tar.bz2
pipeworks-44bafb844ac2497cab683f8a27c9c673f3a0b437.tar.xz
pipeworks-44bafb844ac2497cab683f8a27c9c673f3a0b437.zip
use nodetimers instead of abm's to run the autocrafters; only run autocrafters when needed
autocrafters will stop() when theres no valid recipe, no dst space or enough src material it will resume again on inventory or recipe changes
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
})