Skip to content

Instantly share code, notes, and snippets.

@DataKinds
Last active March 11, 2026 09:17
Show Gist options
  • Select an option

  • Save DataKinds/cc4c04985662595a0b36c8ad55c45642 to your computer and use it in GitHub Desktop.

Select an option

Save DataKinds/cc4c04985662595a0b36c8ad55c45642 to your computer and use it in GitHub Desktop.
INVENTORY_CHANGE_DEBOUNCE_TIME = 1 -- seconds
CHEST_COUNT = 2
VERBOSE = true
local pp = (require "cc.pretty").pretty_print
-- example item storage:
-- {
-- {
-- count = 16,
-- name = "minecraft:ink_sac"
-- },
-- {
-- count = 1,
-- name = "minecraft:crossbow"
-- nbt = "23y53489h5345345349875347"
-- }
-- }
local turtle_items = {}
local cold_items = {}
function tableLength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
-- items will be reported in separate stacks normally
-- this will also handle sparse item stacks
-- this function outputs an object keyed on `<item name>:<nbt>`
function mergeItemStacks(item_list)
return appendItemStack({}, item_list)
end
function appendItemStack(pre_merged_items, item_list)
for slot, item in pairs(item_list) do
local key = item.name
if item.nbt ~= nil then
key = key .. ":" .. item.nbt
end
if pre_merged_items[key] == nil then
pre_merged_items[key] = item
else
pre_merged_items[key].count = pre_merged_items[key].count + item.count
end
end
return pre_merged_items
end
function getTurtleItems()
out = {}
for i=2,16 do
table.insert(out, turtle.getItemDetail(i))
end
return mergeItemStacks(out)
end
function indexColdItems()
print("Indexing cold storage...")
cold_items = {}
local items_by_idem_key = {}
for block_offset=1,CHEST_COUNT do
visitChest(block_offset)
local chest = peripheral.find("inventory")
local chest_item_list = chest.list()
for k, _ in pairs(chest_item_list) do
chest_item_list[k].cold_block_offset = block_offset -- TODO: this should be able to have multiple offsets
end
items_by_idem_key = appendItemStack(items_by_idem_key, chest.list())
returnHome()
end
for _,item in pairs(items_by_idem_key) do
table.insert(cold_items, item)
end
pp(cold_items)
print("Done indexing.")
drawColdItemList()
end
function setNormalColors()
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.black)
end
local cold_item_list_scroll_offset = 0
local cold_item_list_search_term = "SEARCH TERM"
local cold_item_list_highlighted_key
function drawColdItemList()
setNormalColors()
term.clear()
-- draw scrollable item list
for item_idx, item in ipairs(cold_items) do
term.setCursorPos(2,3+cold_item_list_scroll_offset+item_idx-1)
if item_idx == cold_item_list_highlighted_key then
term.setBackgroundColor(colors.green)
else
setNormalColors()
end
term.write(item.name .. " x " .. item.count)
end
-- draw search box
setNormalColors()
term.setCursorPos(1,1)
term.write("> ")
term.write(cold_item_list_search_term)
term.setCursorBlink(true)
end
function clickColdItemList(click_x, click_y)
clicked_key = click_y - cold_item_list_scroll_offset - 2
if clicked_key == cold_item_list_highlighted_key then
-- if the user double clicked a list item
visitChest(cold_items[clicked_key].cold_block_offset)
sleep(3)
returnHome()
cold_item_list_highlighted_key = nil
else
cold_item_list_highlighted_key = clicked_key
end
end
local visited_block
function visitChest(block_offset)
turtle.turnRight()
for idx=1,block_offset do
turtle.forward()
end
turtle.turnLeft()
visited_block = block_offset
end
function returnHome()
turtle.turnLeft()
for idx=1,visited_block do
turtle.forward()
end
turtle.turnRight()
end
local inv_change_timer
function turtleInventoryEvent()
print("Inventory changed. Waiting...")
if inv_change_timer ~= nil then
os.cancelTimer(inv_change_timer)
end
inv_change_timer = os.startTimer(INVENTORY_CHANGE_DEBOUNCE_TIME)
end
function turtleDebouncedInventoryEvent()
print("Done waiting!")
turtle_items = getTurtleItems()
if VERBOSE then pp(turtle_items) end
print(("Storing %d items..."):format(tableLength(turtle_items)))
indexColdItems()
end
function timerRouter(timer_id)
if timer_id == inv_change_timer then
turtleDebouncedInventoryEvent()
end
end
function mainEventLoop()
local evData = {os.pullEvent()}
local ev = evData[1]
if ev == "turtle_inventory" then
turtleInventoryEvent()
elseif ev == "timer" then
timerRouter(evData[2])
elseif ev == "mouse_scroll" and evData[2] == -1 then
-- scroll up
cold_item_list_scroll_offset = cold_item_list_scroll_offset + 1
drawColdItemList()
elseif ev == "mouse_scroll" and evData[2] == 1 then
-- scroll down
cold_item_list_scroll_offset = cold_item_list_scroll_offset - 1
drawColdItemList()
elseif ev == "mouse_click" then
clickColdItemList(evData[3], evData[4])
drawColdItemList()
paintutils.drawPixel(evData[3], evData[4], colors.red)
end
end
while true do
mainEventLoop()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment