mirror of
				https://github.com/mt-mods/pipeworks.git
				synced 2025-11-04 08:55:30 +01:00 
			
		
		
		
	Fix handling of split stacks (#167)
This commit is contained in:
		@@ -257,7 +257,6 @@ local function punch_filter(data, filtpos, filtnode, msg)
 | 
			
		||||
	if fromtube.before_filter then fromtube.before_filter(frompos) end
 | 
			
		||||
 | 
			
		||||
	local function grabAndFire(frominvname, filterfor)
 | 
			
		||||
		if (exmatch_mode ~= 0) and not filterfor.count then return false end
 | 
			
		||||
		local sposes = {}
 | 
			
		||||
		if not frominvname or not frominv:get_list(frominvname) then return end
 | 
			
		||||
		for spos,stack in ipairs(frominv:get_list(frominvname)) do
 | 
			
		||||
@@ -314,7 +313,8 @@ local function punch_filter(data, filtpos, filtnode, msg)
 | 
			
		||||
				return a < b
 | 
			
		||||
			end)
 | 
			
		||||
		end
 | 
			
		||||
		local taken = 0
 | 
			
		||||
		local available_items = {}
 | 
			
		||||
		local available_count = 0
 | 
			
		||||
		for _, spos in ipairs(sposes) do
 | 
			
		||||
			local stack = frominv:get_stack(frominvname, spos)
 | 
			
		||||
			local doRemove = stack:get_count()
 | 
			
		||||
@@ -336,50 +336,60 @@ local function punch_filter(data, filtpos, filtnode, msg)
 | 
			
		||||
				local count
 | 
			
		||||
				if data.stackwise then
 | 
			
		||||
					count = math.min(stack:get_count(), doRemove)
 | 
			
		||||
					taken = taken + count
 | 
			
		||||
					if filterfor.count and (filterfor.count > 1 or data.digiline) then
 | 
			
		||||
						count = math.min(filterfor.count - available_count, count)
 | 
			
		||||
					end
 | 
			
		||||
					table.insert(available_items, {spos = spos, count = count})
 | 
			
		||||
					available_count = available_count + count
 | 
			
		||||
					if not filterfor.count or available_count >= filterfor.count then
 | 
			
		||||
						break
 | 
			
		||||
					end
 | 
			
		||||
				else
 | 
			
		||||
					taken = 1
 | 
			
		||||
					break
 | 
			
		||||
					table.insert(available_items, {spos = spos, count = 1})
 | 
			
		||||
					available_count = 1
 | 
			
		||||
					break  -- only one item allowed so ignore other stacks
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		local item
 | 
			
		||||
		if taken == 0 then return false end
 | 
			
		||||
		if (exmatch_mode ~= 0) and (filterfor.count > taken) then return false end
 | 
			
		||||
		if filterfor.count then taken = math.min(taken, filterfor.count) end
 | 
			
		||||
		local real_taken = 0
 | 
			
		||||
		if fromtube.remove_items then
 | 
			
		||||
			for i, spos in ipairs(sposes) do
 | 
			
		||||
				-- it could be the entire stack...
 | 
			
		||||
				item = fromtube.remove_items(frompos, fromnode, frominv:get_stack(frominvname, spos), dir, taken, frominvname, spos)
 | 
			
		||||
				local count = math.min(taken, item:get_count())
 | 
			
		||||
				taken = taken - count
 | 
			
		||||
				real_taken = real_taken + count
 | 
			
		||||
				if taken == 0 then break end
 | 
			
		||||
				if not filterfor.count then break end
 | 
			
		||||
			end
 | 
			
		||||
		else
 | 
			
		||||
			for i, spos in ipairs(sposes) do
 | 
			
		||||
				-- it could be the entire stack...
 | 
			
		||||
				local stack = frominv:get_stack(frominvname, spos)
 | 
			
		||||
				local count = math.min(taken, stack:get_count())
 | 
			
		||||
				item = stack:take_item(taken)
 | 
			
		||||
				frominv:set_stack(frominvname, spos, stack)
 | 
			
		||||
		if available_count == 0 or (exmatch_mode ~= 0 and filterfor.count and available_count < filterfor.count) then
 | 
			
		||||
			return false -- not enough, fail
 | 
			
		||||
		end
 | 
			
		||||
		local taken_stacks = {}
 | 
			
		||||
		for _,item in ipairs(available_items) do
 | 
			
		||||
			local stack = frominv:get_stack(frominvname, item.spos)
 | 
			
		||||
			local taken
 | 
			
		||||
			if fromtube.remove_items then
 | 
			
		||||
				taken = fromtube.remove_items(frompos, fromnode, stack, dir, item.count, frominvname, item.spos)
 | 
			
		||||
			else
 | 
			
		||||
				taken = stack:take_item(item.count)
 | 
			
		||||
				frominv:set_stack(frominvname, item.spos, stack)
 | 
			
		||||
				if fromdef.on_metadata_inventory_take then
 | 
			
		||||
					fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakeplayer)
 | 
			
		||||
					fromdef.on_metadata_inventory_take(frompos, frominvname, item.spos, taken, fakeplayer)
 | 
			
		||||
				end
 | 
			
		||||
				taken = taken - count
 | 
			
		||||
				real_taken = real_taken + count
 | 
			
		||||
				if taken == 0 then break end
 | 
			
		||||
				if not filterfor.count then break end
 | 
			
		||||
			end
 | 
			
		||||
			if not taken:is_empty() then
 | 
			
		||||
				table.insert(taken_stacks, taken)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		local pos = vector.add(frompos, vector.multiply(dir, 1.4))
 | 
			
		||||
		local start_pos = vector.add(frompos, dir)
 | 
			
		||||
		item:set_count(real_taken)
 | 
			
		||||
		pipeworks.tube_inject_item(pos, start_pos, dir, item,
 | 
			
		||||
			fakeplayer:get_player_name(), item_tags)
 | 
			
		||||
		return true -- only fire one item, please
 | 
			
		||||
		if #taken_stacks > 1 then
 | 
			
		||||
			-- merge stacks if possible to reduce items in tubes
 | 
			
		||||
			local merged = {}
 | 
			
		||||
			for _,a in ipairs(taken_stacks) do
 | 
			
		||||
				for _,b in ipairs(merged) do
 | 
			
		||||
					a = b:add_item(a)
 | 
			
		||||
				end
 | 
			
		||||
				if not a:is_empty() then
 | 
			
		||||
					table.insert(merged, a)
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			taken_stacks = merged
 | 
			
		||||
		end
 | 
			
		||||
		for _,stack in ipairs(taken_stacks) do
 | 
			
		||||
			local pos = vector.add(frompos, vector.multiply(dir, 1.4))
 | 
			
		||||
			local start_pos = vector.add(frompos, dir)
 | 
			
		||||
			pipeworks.tube_inject_item(pos, start_pos, dir, stack, fakeplayer:get_player_name(), item_tags)
 | 
			
		||||
		end
 | 
			
		||||
		return true
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user