From 4249accea0624e3052a09ee41187e1837c79a75a Mon Sep 17 00:00:00 2001 From: Zenon Seth Date: Sun, 21 Jul 2024 10:57:42 +0100 Subject: [PATCH] Fix take_stack_from_network to account for partially fulfilled requests --- logic/access_point_formspec.lua | 4 ++-- logic/network_storage.lua | 32 ++++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/logic/access_point_formspec.lua b/logic/access_point_formspec.lua index 860e5ad..54b7701 100644 --- a/logic/access_point_formspec.lua +++ b/logic/access_point_formspec.lua @@ -409,8 +409,8 @@ function logistica.access_point_on_take(inv, listname, index, stack, player) logistica.take_stack_from_network(stack, network, acceptTaken, false, false, false) else -- we want to take the actual item, with exact metadata, always - -- because the on_take method should have placed the exact item in the slot already - local takeResult = logistica.take_stack_from_network(stack, network, acceptTaken, false, true, false) + -- because the allow_take method should have placed the exact item in the slot already + logistica.take_stack_from_network(stack, network, acceptTaken, false, true, false) end -- refresh the page in case we had to swap out a fake item or a stack is gone show_access_point_formspec(pos, player:get_player_name()) diff --git a/logic/network_storage.lua b/logic/network_storage.lua index 86b71ea..0b19d0f 100644 --- a/logic/network_storage.lua +++ b/logic/network_storage.lua @@ -93,28 +93,40 @@ function logistica.take_stack_from_network(stackToTake, network, collectorFunc, if not depth then depth = 0 end if depth > MAX_NETWORK_DEPTH_SEARCH then return ret(false, "Too many crafting suppliers recursively using each other, limit reached") end if not network then return ret(false, "No connected network") end + + local takeStack = ItemStack(stackToTake) + local internalCollectorFunc = function(st) + local leftover = collectorFunc(st) + if leftover > 0 then + takeStack:set_count(0) -- because if there are leftover, we terminate early + else + takeStack:set_count(math.max(0, takeStack:get_count() - st:get_count())) + end + return leftover + end + -- first check normal suppliers only local suppliersCheck = - logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "normal") - if suppliersCheck.success then return ret(true) end + logistica.take_stack_from_suppliers(takeStack, network, internalCollectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "normal") + if takeStack:is_empty() or suppliersCheck.success then return ret(true) end -- then check storages local storageCheck = {success = false} - if stackToTake:get_stack_max() <= 1 then - storageCheck = logistica.take_stack_from_item_storage(stackToTake, network, collectorFunc, isAutomatedRequest, useMetadata, dryRun) + if takeStack:get_stack_max() <= 1 then + storageCheck = logistica.take_stack_from_item_storage(takeStack, network, internalCollectorFunc, isAutomatedRequest, useMetadata, dryRun) else - storageCheck = logistica.take_stack_from_mass_storage(stackToTake, network, collectorFunc, isAutomatedRequest, dryRun) + storageCheck = logistica.take_stack_from_mass_storage(takeStack, network, internalCollectorFunc, isAutomatedRequest, dryRun) end - if storageCheck.success then return ret(true) end + if takeStack:is_empty() or storageCheck.success then return ret(true) end -- finally check bucket and crafting suppliers local bucketSuppliersCheck = - logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "bucket") - if bucketSuppliersCheck.success then return ret(true) end + logistica.take_stack_from_suppliers(takeStack, network, internalCollectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "bucket") + if takeStack:is_empty() or bucketSuppliersCheck.success then return ret(true) end local craftingSuppliersCheck = - logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "crafting") - if craftingSuppliersCheck.success then return ret(true) end + logistica.take_stack_from_suppliers(takeStack, network, internalCollectorFunc, isAutomatedRequest, useMetadata, dryRun, depth, "crafting") + if takeStack:is_empty() or craftingSuppliersCheck.success then return ret(true) end -- iffy, but specific suppliers error are more important than mass storage ones if not bucketSuppliersCheck.success and bucketSuppliersCheck.error and bucketSuppliersCheck.error ~= "" then