ccVault/main.lua
2024-10-16 23:47:54 +02:00

231 lines
6.3 KiB
Lua

local reindexFreq = 1 -- Per minute (0.5 to index every 2 minutes, ...)
local indexUpdated = false
local items
local outputSlots
local item -- User choice
local count -- User choice
local chests = { peripheral.find("inventory") }
for i, chest in ipairs(chests) do
if peripheral.getName(chest) == settings.get("ccVault.outputInventory") then
table.remove(chests, i)
break
end
end
-- Functions
local getOutputSize
local indexChests
local loadIndex
local getItemNames
local userInput
local indexRefresh
local storageLoop
local transfer
function getOutputSize()
if peripheral.getType(settings.get("ccVault.outputInventory")) == "create:depot" then
outputSlots = 1
else
outputSlots = peripheral.call(settings.get("ccVault.outputInventory"), "size")
end
end
-- Function to populate the index
function indexChests()
while true do
local itemIndex = {}
for _, chest in ipairs(chests) do
for slot, item in pairs(chest.list()) do
if not itemIndex[item.name] then
itemIndex[item.name] = {}
end
table.insert(itemIndex[item.name], { chest = peripheral.getName(chest), slot = slot })
end
end
if fs.exists(settings.get("ccVault.file")) then
local db = fs.open(settings.get("ccVault.file"), "r")
if not db then
printError("Couldn't open index databse!")
else
if textutils.unserializeJSON(db.readAll()) == itemIndex then
db.close()
else
db.close()
db = fs.open(settings.get("ccVault.file"), "w")
if not db then
printError("Couldn't write index databse!")
else
db.write(textutils.serializeJSON(itemIndex))
db.close()
indexUpdated = true
end
end
end
else
local db = fs.open(settings.get("ccVault.file"), "w")
db = fs.open(settings.get("ccVault.file"), "w")
if not db then
printError("Couldn't write index databse!")
else
db.write(textutils.serializeJSON(itemIndex))
db.close()
indexUpdated = true
end
end
sleep(60 / reindexFreq)
end
end
function loadIndex()
local itemIndex
local db = fs.open(settings.get("ccVault.file"), "r")
if not db then
-- printError("Couldn't open DB file!\n" .. settings.get("ccVault.file"))
print("Index file not found. It probably wasn't created yet.")
local iCount = 0
write("Waiting until indexing is finished")
while not db do
if iCount >= 3 then
term.setCursorPos(term.getCursorPos[1], 1)
write("Waiting until indexing is finished.")
iCount = 0
else
write(".")
iCount = iCount + 1
end
db = fs.open(settings.get("ccVault.file"), "r")
sleep(5)
end
end
itemIndex = textutils.unserializeJSON(db.readAll())
db.close()
term.clear()
term.setCursorPos(1, 1)
return itemIndex
end
function indexRefresh()
sleep(60 / reindexFreq)
end
function storageLoop()
local itemIndex = loadIndex()
while true do
if indexUpdated then
itemIndex = loadIndex()
indexUpdated = false
end
items = getItemNames(itemIndex)
parallel.waitForAny(userInput, indexRefresh)
if item then
if count == 0 or not count then count = 64 end
transfer(item, count, itemIndex)
item = nil
count = nil
end
sleep(2)
term.clear()
term.setCursorPos(1, 1)
end
end
---@param tItem string
---@param maxCount integer
---@param itemIndex table
function transfer(tItem, maxCount, itemIndex)
local transfered = 0
-- Stored item info
local exists = itemIndex[tItem] ~= nil
if exists then
exists = itemIndex[tItem][1]
end
if not exists then
print("Item not found.\nTry to wait for index update.")
return
end
local sItemInfo = peripheral.call(itemIndex[tItem][1]["chest"], "getItemDetail", itemIndex[tItem][1]["slot"])
if not sItemInfo then
print("Index is out of date!\nWait for index update to resolve this error.")
return
elseif sItemInfo.count <= 0 then
print("Index is out of date!\nWait for index update to resolve this error.")
return
elseif not sItemInfo.count then
print("Index is out of date!\nWait for index update to resolve this error.")
return
end
while transfered < count do
if not itemIndex[tItem][1] then
if transfered > 0 then
print("Not enough of `" .. tItem .. "` was found.\nTransfered only " .. transfered .. ".")
end
break
end
---@type ccTweaked.peripheral.item
local lastSlot = peripheral.call(settings.get("ccVault.outputInventory"), "getItemDetail", outputSlots)
if lastSlot then
if lastSlot.count > 0 then
print("Output inventory is full!")
return
end
end
if sItemInfo.name == tItem then
local moved = peripheral.call(itemIndex[tItem][1]["chest"], "pushItems", settings.get("ccVault.outputInventory"),
itemIndex[tItem][1]["slot"],
maxCount)
if moved == sItemInfo.count then
transfered = transfered + moved
table.remove(itemIndex[tItem], 1)
elseif moved == 0 then
if peripheral.call(settings.get("ccVault.outputInventory"), "size") == transfered then
print("Output inventory is full!")
break
else
table.remove(itemIndex[tItem], 1)
end
elseif not moved then
print("Item not found!")
break
else
transfered = transfered + moved
end
else
table.remove(itemIndex[tItem], 1)
end
end
end
---@param itemIndex table -- Index table of all the items
---@return table names Table of strings
function getItemNames(itemIndex)
local names = {}
for name, _ in pairs(itemIndex) do
table.insert(names, name)
end
return names
end
---@param items table Table of all item names as strings
function userInput()
local completion = require "cc.completion"
local input = read(nil, nil, function(text) return completion.choice(text, items) end)
if not input then item, count = nil, nil end
input = input .. " "
local parsedInput = {}
for w in input:gmatch("(.-) ") do table.insert(parsedInput, w) end
-- item, count = string.match(input, "([^%s]+) (%d+)")
item = parsedInput[1]
count = tonumber(parsedInput[2])
end
getOutputSize()
parallel.waitForAny(indexChests, storageLoop)