diff options
author | Tim <t4im@users.noreply.github.com> | 2015-01-27 03:45:38 +0100 |
---|---|---|
committer | Tim <t4im@users.noreply.github.com> | 2015-01-27 23:41:46 +0100 |
commit | 44bafb844ac2497cab683f8a27c9c673f3a0b437 (patch) | |
tree | 8c6abccbaeb450d2e9f71b5056b50f98ffd89e6a /autocrafter.lua | |
parent | 2ccce52976a9c11313486ef3602c002b757f0dbe (diff) |
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.lua | 131 |
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 }) |