Aaron Suen 5768317269 Make pickup and rearrange logic consistent again.
The new change preserves uncombined stacks when digging.  For
example, if you have dirt on the far right, tools on the far left,
and space between, and you dig dirt with the tools on the left,
it will create a NEW stack in the space between BEFORE it reaches
the dirt on the far right.

This behavior is necessary to ensure we can keep stacks separate
that we've separated for a specific purpose.

We also can't make the behavior vary based on whether using a tool
or not, because this would be even MORE jarring.
2019-03-29 18:44:01 -04:00

83 lines
2.0 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, ipairs, minetest, nodecore
= ItemStack, ipairs, minetest, nodecore
-- LUALOCALS > ---------------------------------------------------------
local cache = {}
local function handlepickups(player)
local inv = player:get_inventory()
local pname = player:get_player_name()
local cached = cache[pname]
if cached then
local snap = {}
for i = 1, #cached do snap[i] = ItemStack(cached[i]) end
local excess = {}
local dirty
local widx = player:get_wield_index()
for i in nodecore.inv_walk(player, widx, inv) do
local cur = inv:get_stack("main", i)
local old = snap[i]
if old:is_empty() or cur:peek_item(1):to_string()
== old:peek_item(1):to_string() then
local def = minetest.registered_items[cur:get_name()]
if not (def and def.virtual_item) then
local cc = cur:get_count()
local oc = old:get_count()
if cc > oc then
cur:set_count(cc - oc)
for i = 1, #excess do
cur = excess[i]:add_item(cur)
end
if not cur:is_empty() then
excess[#excess + 1] = cur
end
dirty = dirty or i ~= widx
else
snap[i] = cur
end
end
else
snap[i] = cur
end
end
if dirty then
for i = 1, #excess do
local v = excess[i]
for j in nodecore.inv_walk(player, widx, inv) do
v = snap[j]:add_item(v)
end
if not v:is_empty() then
minetest.log("failed to reinsert item "
.. v:get_name() .. " " .. v:get_count()
.. " for " .. pname)
dirty = nil
end
end
end
if dirty then
dirty = nil
for i = 1, #cached do
dirty = dirty or inv:get_stack("main", i)
:to_string() ~= snap[i]:to_string()
end
end
if dirty then
minetest.log("inventory rearranged for " .. pname)
inv:set_list("main", snap)
end
end
cache[pname] = inv:get_list("main")
end
minetest.register_globalstep(function()
for _, p in ipairs(minetest.get_connected_players()) do
handlepickups(p)
end
end)