Aaron Suen 3c5d7e200b "Family" stacking API
If items have a common "stackfamily" property in definition, then
they combine stacks; name and metadata are effectively ignored and
any name is considered acceptable for the combined stack name.

This is used by Lux to allow it to stack naturally instead of the
player having to lay them out spaced on the ground to "cool" them
all to the same level, since all Lux changes dynamically anyway.
2019-08-30 22:36:44 -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 = nodecore.stack_merge(excess[i], 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 = nodecore.stack_merge(snap[j], 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)