Implement ItemStack grouping

This commit is contained in:
Gabriel Tofvesson 2024-10-04 15:03:08 +02:00
parent 55ec42bffb
commit a13cbe5bd5

151
storage/itemgroup.lua Normal file

@ -0,0 +1,151 @@
local ItemGroup = {}
ItemGroup.__index = ItemGroup
--- Create a group of managed itemstacks
---@param stack table ItemStack to compare to
---@return table ItemGroup instance representing stack type
function ItemGroup:from(stack)
local obj = { stack }
setmetatable(obj, self)
obj.__index = obj
return obj
end
function ItemGroup.collectStacks(stacks)
local groups = {}
for _,stack in ipairs(stacks) do
for _,group in ipairs(groups) do
if group:addStack(stack) then
goto continue
end
end
table.insert(groups, ItemGroup:from(stack))
::continue::
end
return groups
end
function ItemGroup:getStackCount()
return #self
end
function ItemGroup:getDisplayName()
return self:_getIdentityStack():getDisplayName()
end
function ItemGroup:getName()
return self:_getIdentityStack():getName()
end
function ItemGroup:getEnchantments()
return self:_getIdentityStack():getEnchantments()
end
function ItemGroup:_getIdentityStack()
return self[1]
end
function ItemGroup:_iterateStacks()
return ipairs(self)
end
function ItemGroup:_addStack(stack)
table.insert(self, stack)
end
function ItemGroup:_removeStack(stackOrIndex)
if type(stackOrIndex) == "number" then
return table.remove(self, stackOrIndex) ~= nil
else
for index,stack in self:_iterateStacks() do
if stack == stackOrIndex then
return self:_removeStack(index)
end
end
end
end
function ItemGroup:canAddStack(stack)
if self:_getIdentityStack():canTransfer(stack) then
for _,chkStack in self:_iterateStacks() do
if chkStack == stack then
-- Already in the group
return true
end
end
self:_addStack(stack)
return true
end
return false
end
function ItemGroup:addStack(stack)
if self:canAddStack(stack) then
self:_addStack(stack)
return true
end
return false
end
function ItemGroup:getItemCount()
if self:_getIdentityStack():isEmpty() then
return 0
end
local sum = 0
for _,stack in self:_iterateStacks() do
sum = sum + stack:getCount()
end
return sum
end
function ItemGroup:_copyTrackedStackList()
local collect = {}
for index,stack in self:_iterateStacks() do
table.insert(collect, { stack = stack, index = index })
end
return collect
end
function ItemGroup:defragment()
if self:_getIdentityStack():isEmpty() then
return 0
end
local entries = self:_copyStackList()
table.sort(entries, function(a, b)
return a.stack:getCount() > b.stack:getCount()
end)
local endPtr = #entries
local startPtr = endPtr
for i=1,endPtr do
local entry = entries[i].stack
if entry:getMaxCount() ~= entry:getCount() then
startPtr = i
end
end
local toRemove = {}
while startPtr < endPtr do
local from = entries[endPtr]
local to = entries[startPtr]
local emptied, _ = from.stack:transferTo(to.stack)
if emptied then
table.insert(toRemove, from.index)
endPtr = endPtr - 1
end
if (not emptied) or (to.stack:getCount() == to.stack:getMaxCount()) then
startPtr = startPtr + 1
end
end
table.sort(toRemove, function(a, b) return a > b end)
for _,index in ipairs(toRemove) do
self:_removeStack(index)
end
return #toRemove
end
return ItemGroup