From 44bafb844ac2497cab683f8a27c9c673f3a0b437 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 27 Jan 2015 03:45:38 +0100 Subject: 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 --- autocrafter.lua | 131 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 60 deletions(-) (limited to 'autocrafter.lua') 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 }) -- cgit v1.2.3