Fix autocrafter not taking enough items if number of needed items of a kind > stack...
authorNovatux <nathanael.courant@laposte.net>
Wed, 30 Oct 2013 07:33:09 +0000 (08:33 +0100)
committerNovatux <nathanael.courant@laposte.net>
Wed, 30 Oct 2013 07:33:34 +0000 (08:33 +0100)
autocrafter.lua

index 164f6fe828a5b20b351f1df2f07e1fdd2b05665a..1f2d9e519e74cef631e4539018a19bc441ae88a8 100644 (file)
@@ -1,51 +1,59 @@
 local autocrafterCache = {}  -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second
 
+local function make_inventory_cache(invlist)
+       local l = {}
+       for _, stack in ipairs(invlist) do
+               l[stack:get_name()] = (l[stack:get_name()] or 0) + stack:get_count()
+       end
+       return l
+end
+
 function autocraft(inventory, pos)
        local recipe = inventory:get_list("recipe")
-               local recipe_last
-               local result
-               local new
+       local recipe_last
+       local result
+       local new
 
-               if autocrafterCache[minetest.hash_node_position(pos)] == nil then
-                       --print("first call for this autocrafter at pos("..pos.x..","..pos.y..","..pos.z..")")
-                       recipe_last = {}
-                       for i = 1, 9 do
-                               recipe_last[i] = recipe[i]
-                               --print (recipe_last[i]:get_name())
-                               recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1})
+       if autocrafterCache[minetest.hash_node_position(pos)] == nil then
+               --print("first call for this autocrafter at pos("..pos.x..","..pos.y..","..pos.z..")")
+               recipe_last = {}
+               for i = 1, 9 do
+                       recipe_last[i] = recipe[i]
+                       --print (recipe_last[i]:get_name())
+                       recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1})
+               end
+               result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
+               autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new}
+       else
+               local autocrafterCacheEntry = autocrafterCache[minetest.hash_node_position(pos)]
+               recipe_last = autocrafterCacheEntry["recipe"]
+               result = autocrafterCacheEntry["result"]
+               new = autocrafterCacheEntry["new"]
+               local recipeUnchanged = true
+               for i = 1, 9 do
+                       if recipe[i]:get_name() ~= recipe_last[i]:get_name() then
+                               recipeUnchanged = False
+                               break
                        end
-                       result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
-                       autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new}
+                       if recipe[i]:get_count() ~= recipe_last[i]:get_count() then
+                               recipeUnchanged = False
+                               break
+                       end
+               end
+               if recipeUnchanged then
+                       --print("autocrafter recipe unchanged")
                else
-                       local autocrafterCacheEntry = autocrafterCache[minetest.hash_node_position(pos)]
-                       recipe_last = autocrafterCacheEntry["recipe"]
-                       result = autocrafterCacheEntry["result"]
-                       new = autocrafterCacheEntry["new"]
-                       local recipeUnchanged = true
+                       --print("autocrafter recipe changed at pos("..pos.x..","..pos.y..","..pos.z..")")
                        for i = 1, 9 do
-                               if recipe[i]:get_name() ~= recipe_last[i]:get_name() then
-                                       recipeUnchanged = False
-                                       break
-                               end
-                               if recipe[i]:get_count() ~= recipe_last[i]:get_count() then
-                                       recipeUnchanged = False
-                                       break
-                               end
-                       end
-                       if recipeUnchanged then
-                               --print("autocrafter recipe unchanged")
-                       else
-                               --print("autocrafter recipe changed at pos("..pos.x..","..pos.y..","..pos.z..")")
-                               for i = 1, 9 do
-                                               recipe_last[i] = recipe[i]
-                                               recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1})
-                               end
-                               result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
-                               autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new}
+                                       recipe_last[i] = recipe[i]
+                                       recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1})
                        end
+                       result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
+                       autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new}
                end
+       end
 
-               local input = inventory:get_list("input")
+       local input = inventory:get_list("input")
        if result.item:is_empty() then return end
        result = result.item
        if not inventory:room_for_item("dst", result) then return end
@@ -59,14 +67,14 @@ function autocraft(inventory, pos)
                        end
                end
        end
-       local stack
+       local invcache = make_inventory_cache(inventory:get_list("src"))
        for itemname, number in pairs(to_use) do
-               stack = ItemStack({name = itemname, count = number})
-               if not inventory:contains_item("src", stack) then return end
+               if (not invcache[itemname]) or invcache[itemname] < number then return end
        end
        for itemname, number in pairs(to_use) do
-               stack = ItemStack({name = itemname, count = number})
-               inventory:remove_item("src", stack)
+               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))
+               end
        end
        inventory:add_item("dst", result)
        for i = 1, 9 do