HEIGHT = 2 -- number of chests tall DEPTH = 3 -- number of columns of chests CONTAINER_SIZE = 10 -- size of a single double-chest local database = { items = {}, -- item to amount and locations containers = {}, -- location to item } -- database.items = { -- ["minecraft:stick;0"] = { -- amount = 200, -- max_stack = 64, -- locations = { -- {1,1,10,64}, -- x, y, slot, amount -- {1,3,54,64}, -- {10,2,2,20} -- } -- } -- } -- database.containers = { -- array of columns in the storage wall -- { -- array of containers in a column -- { -- arrays of slots in the container -- false, true, nil, nil, nil -- if the slot is occupied (true) or not (nil|false) -- }, -- { -- }, -- }, -- { -- } -- } local function lookup(searched_item) return database.items[searched_item] end ---find the first empty slot in storage ---return nil if inventory is full (no empty slots) ---@param begin_x integer start searching from this x ---@param begin_y integer start searching from this y ---@param begin_slot integer start searching from this slot ---@return integer|nil x ---@return integer|nil y ---@return integer|nil slot local function find_empty_slot(begin_x, begin_y, begin_slot) local x = begin_x local y = begin_y local slot = begin_slot while true do if not database.containers[x] or not database.containers[x][y] or not database.containers[x][y][slot] then return x, y, slot end slot = slot + 1 if slot > CONTAINER_SIZE then slot = 1 y = y + 1 if y > HEIGHT then y = 1 x = x + 1 if x > DEPTH then return nil end -- if not database.containers[x] then -- return x, 1, 1 -- end end -- if not database.containers[x][y] then -- return x, y, 1 -- end end -- if not database.containers[x][y][slot] then -- return x, y, slot -- end end end ---mark the given slot as occupied or not ---@param x integer ---@param y integer ---@param slot integer ---@param occupied boolean local function mark_slot(x, y, slot, occupied) local column = database.containers[x] if not column then column = {} database.containers[x] = column end local container = column[y] if not container then container = {} column[y] = container end -- flag the slot as occupied container[slot] = occupied end ---@param item string ---@param amount integer ---@param max_stack integer ---@return table db_item local function create_db_item(item, amount, max_stack) local db_item = { amount = amount, max_stack = max_stack, locations = {} } database.items[item] = db_item return db_item end ---@param db_item table ---@param amount integer ---@param location_index integer|nil local function transfer_to_location(db_item, amount, location_index) local location = db_item.locations[location_index] print('Transfering ' .. amount .. ' to slot ' .. location[1] .. ',' .. location[2] .. ',' .. location[3]) db_item.amount = db_item.amount + amount location[4] = location[4] + amount end ---@param db_item table ---@param amount integer ---@param x integer ---@param y integer ---@param slot integer local function transfer_to_empty_slot(db_item, amount, x, y, slot) print('Transfering ' .. amount .. ' to slot ' .. x .. ',' .. y .. ',' .. slot) db_item.amount = db_item.amount + amount db_item.locations[#db_item.locations + 1] = { x, y, slot, amount } mark_slot(x, y, slot, true) end ---comment ---@param item string ---@param amount integer ---@param max_stack integer ---@return boolean success local function insert(item, amount, max_stack) print('\nInserting') local db_item = lookup(item) if not db_item then db_item = create_db_item(item, amount, max_stack) end -- try to fill slots where the item already is for location_index, location in ipairs(db_item.locations) do if location[4] < db_item.max_stack then local can_fit = math.min(amount, db_item.max_stack - location[4]) -- print('Can fit ' .. can_fit .. ' into ', table.unpack(location)) transfer_to_location(db_item, can_fit, location_index) amount = amount - can_fit if amount <= 0 then break end end end -- didn't fit to existing slots -> occupy an empty slot local empty_x = 1 local empty_y = 1 local empty_slot = 1 while amount > 0 do empty_x, empty_y, empty_slot = find_empty_slot(empty_x, empty_y, empty_slot) if not empty_x or not empty_y or not empty_slot then print('Inventory full') return false end local can_fit = math.min(amount, max_stack) transfer_to_empty_slot(db_item, can_fit, empty_x, empty_y, empty_slot) amount = amount - can_fit end if amount < 0 then print('Something went horribly wrong - amount is ' .. amount) end return true end print(find_empty_slot(1, 1, 1)) for _ = 1, 20 do print(insert('stick', 61, 64)) print('Next empty:', find_empty_slot(1, 1, 1)) end -- return { -- insert -- }