Skip to content

Instantly share code, notes, and snippets.

@object-Object
Last active July 9, 2020 22:42
Show Gist options
  • Save object-Object/b74b42b5360d2190915047c17f5aa34b to your computer and use it in GitHub Desktop.
Save object-Object/b74b42b5360d2190915047c17f5aa34b to your computer and use it in GitHub Desktop.
CC+Plethora wireless storage system
local chestPrefix="minecraft:ironchest_gold_"
local prefix="$"
local prefixPattern="^%"..prefix
local inputInterval=3
local warnInterval=60
local feederInterval=4
local channel=1
local autoFeeder=false
local cachedSlot=false
local index={}
local modem=peripheral.wrap("back")
local modules=peripheral.wrap("manipulator_0")
local inputChest=peripheral.wrap("minecraft:ender chest_0")
local inv
repeat
local success,result=pcall(modules.getInventory)
inv=result
if not success then sleep(10) end
until success
local totalStorage=0
local usedStorage=0
local lastFullWarning=os.clock()-warnInterval-1
local yieldTime=os.clock()
modem.open(channel)
local function yield()
if os.clock()-yieldTime>2 then
os.queueEvent("yield")
os.pullEvent()
yieldTime=os.clock()
end
end
local function strip(name)
return name:gsub("[^%p%s%w]","")
end
local function getName(meta)
return meta.displayName.." - "..meta.name
end
function slots()
return "Slots used: "..usedStorage.."/"..totalStorage
end
function refreshIndex()
index={}
indexLookup={}
totalStorage=0
usedStorage=0
local inventoryList=inputChest.getTransferLocations()
for _,chest in pairs(inventoryList) do
if chest:match(chestPrefix) then
totalStorage=totalStorage+peripheral.call(chest,"size")
local chestID=chest:gsub(chestPrefix,"")
local chestList=peripheral.call(chest,"list")
if chestList then
for slot,_ in pairs(chestList) do
usedStorage=usedStorage+1
local slotMeta=peripheral.call(chest,"getItemMeta",slot)
local name=getName(slotMeta)
if not indexLookup[name] then
indexLookup[name]=#index+1
end
if not index[indexLookup[name]] then
index[indexLookup[name]]={
name=name,
itemId=itemId,
slots={},
count=0
}
end
local indexEntry=index[indexLookup[name]]
if not indexEntry.slots[chestID] then
indexEntry.slots[chestID]={}
end
table.insert(indexEntry.slots[chestID],slot)
indexEntry.count=indexEntry.count+slotMeta.count
yield()
end
end
end
end
if usedStorage<totalStorage then
lastFullWarning=os.clock()-warnInterval-1
end
end
function search(term)
modules.tell("Search results for "..term..":")
local found=0
if term~="" then
for id,entry in ipairs(index) do
if entry.name:lower():match(term:lower()) then
modules.tell("[ "..id.." ] "..strip(entry.name).." ("..entry.count..")")
found=found+1
end
end
end
if found==0 then
modules.tell("No results found.")
end
end
function list()
modules.tell("Item list:")
for id,entry in ipairs(index) do
modules.tell("[ "..id.." ] "..strip(entry.name).." ("..entry.count..")")
end
modules.tell(slots())
end
function transfer(id, num)
local transferred=0
local entry=index[id]
for chestID,slots in pairs(entry.slots) do
local toRemove={}
for slotID,slot in pairs(slots) do
local item=peripheral.call(chestPrefix..chestID,"getItemMeta",slot)
if item and item.count<=num-transferred then
transferred=transferred+inv.pullItems(chestPrefix..chestID,slot)
table.insert(toRemove,slotID)
elseif item then
transferred=transferred+inv.pullItems(chestPrefix..chestID,slot,num-transferred)
end
if transferred==num then break end
yield()
end
for k,v in pairs(toRemove) do
table.remove(slots,v)
usedStorage = usedStorage - 1
end
if transferred==num then break end
end
local displayName=entry.name:gsub(" %- %S+$","")
entry.count=entry.count-transferred
modules.tell("Transferred "..transferred.." "..strip(displayName).." ("..entry.count.." remaining).")
if entry.count==0 then table.remove(index,id) end
end
modules.capture(prefixPattern)
modules.tell("")
modules.tell("CC System loading...")
print("Indexing...")
refreshIndex()
print("Done indexing.")
print(slots())
modules.tell("CC System is online.")
modules.tell(slots())
parallel.waitForAny(
function() -- command handler
while true do
local _,message,pattern,_,_=os.pullEvent("chat_capture")
if pattern==prefixPattern then
modules.tell("")
if message:match(prefixPattern.."reboot") then
-- reboot
modules.tell("Rebooting.")
shell.run("reboot")
elseif message:match(prefixPattern.."feeder") then
-- feeder
autoFeeder=not autoFeeder
if autoFeeder then
modules.tell("Auto-feeder enabled.")
else
modules.tell("Auto-feeder disabled.")
end
elseif message:match(prefixPattern.."g") then
-- get
local num=message:match(prefixPattern.."%S+ .+ (%d+)$") or ""
local term=message:match(prefixPattern.."%S+ (.+) "..num.."$") or message:match(prefixPattern.."%S+ (.+)$") or ""
if num=="" then num=1 end
num=tonumber(num)
if term:gsub("[%d%s]","")=="" then
-- id
term=tonumber(term)
if index[term] then
transfer(term,num)
else
modules.tell("No items found with id "..term.."!")
end
else
-- search
local results={}
for id,entry in ipairs(index) do
if entry.name:lower():match(term:lower()) then
table.insert(results,id)
end
end
if #results==0 then
modules.tell("No items found matching the name "..term.."!")
elseif #results==1 then
transfer(results[1],num)
else
modules.tell("Multiple items found matching the name "..term..":")
for _,id in ipairs(results) do
local entry=index[id]
modules.tell("[ "..id.." ] "..strip(entry.name).." ("..entry.count..")")
end
modules.tell("Type id of desired item, or anything else to cancel.")
modules.capture(".")
local _,choice,_,_,_=os.pullEvent("chat_capture")
choice=tonumber(choice)
if index[choice] then
transfer(choice,num)
else
modules.tell("Cancelled.")
end
modules.uncapture(".")
end
end
elseif message:match(prefixPattern.."s") then
-- search
local term=message:match(prefixPattern.."%S+ (.+)$") or ""
search(term)
elseif message:match(prefixPattern.."r") then
-- re-index
modules.tell("Re-indexing...")
refreshIndex()
modules.tell("Done re-indexing.")
modules.tell(slots())
elseif message:match(prefixPattern.."l") then
-- list
list()
elseif message:match(prefixPattern.."f") then
-- free
modules.tell(slots())
elseif message:match(prefixPattern.."h") then
-- help menu
modules.tell("Commands:")
modules.tell(prefix.."h(elp) - show this menu")
modules.tell(prefix.."s(earch) <search term> - list items matching search term, in the form [ id ] name - id_name (num)")
modules.tell(prefix.."g(et) <id / name> [count] - get count (default: 1) items from the system, matching the id or name")
modules.tell(prefix.."r(efresh) - refresh the item index (you shouldn't need to do this in most cases)")
modules.tell(prefix.."l(ist) - list all items in the system, in the form [ id ] name - id_name (num)")
modules.tell(prefix.."f(ree) - show how many slots in the system are full")
modules.tell(prefix.."reboot - reboot the system")
modules.tell(prefix.."feeder - toggle the auto-feeder")
else
modules.tell("Command "..message:match(prefixPattern.."%S+").." not found.")
end
end
end
end,
function() -- item input handler
while true do
local itemList=inputChest.list()
if next(itemList)~=nil and os.clock()-lastFullWarning>warnInterval then
local transferredItems=false
for slot,item in pairs(itemList) do
local doneTransfer=false
local count=item.count
local transferred=0
local meta = inputChest.getItemMeta(slot)
local name = getName(meta)
local entry = index[indexLookup[name]]
if entry then
for id, pushSlots in pairs(entry.slots) do
for _, pushSlot in pairs(pushSlots) do
local n = inputChest.pushItems(chestPrefix..id,slot,64,pushSlot)
transferred=transferred+n
entry.count=entry.count+n
if transferred>=count then
doneTransfer=true
break
end
end
if doneTransfer then break end
end
end
if transferred<count and not doneTransfer then
local inventoryList=inputChest.getTransferLocations()
for _,chest in pairs(inventoryList) do
if chest:match(chestPrefix) then
local slotList = peripheral.call(chest, "list")
for pushSlot=1, peripheral.call(chest, "size") do
if not slotList[pushSlot] then
local n = inputChest.pushItems(chest,slot,64,pushSlot)
local chestID = chest:gsub(chestPrefix, "")
if entry then
if not entry.slots[chestID] then
entry.slots[chestID] = {}
end
table.insert(entry.slots[chestID], pushSlot)
entry.count = entry.count+n
else
indexLookup[name]=#index+1
index[indexLookup[name]]={
name=name,
itemId=item.name,
slots={[chestID]={pushSlot}},
count=n
}
end
transferred=transferred+n
usedStorage = usedStorage + 1
if transferred>=count then
doneTransfer=true
break
end
end
end
end
if doneTransfer then break end
end
end
if transferred<count then
lastFullWarning=os.clock()
modules.tell("")
modules.tell("WARNING: storage is full!")
modules.tell(slots())
print()
print("WARNING: storage is full!")
print(slots())
end
if transferred>0 and not transferredItems then
transferredItems=true
end
end
end
sleep(inputInterval)
end
end,
function()
while true do
local _,_,sendChannel,replyChannel,message,_=os.pullEvent("modem_message")
if message=="slots" then
modem.transmit(replyChannel,channel,slots())
end
end
end,
function()
while true do
if autoFeeder then
local data=modules.getMetaOwner()
while data.food.hungry do
local item
if cachedSlot then
local slotItem=inv.getItem(cachedSlot)
if slotItem and slotItem.consume then
item=slotItem
else
cachedSlot=nil
end
end
if not item then
for slot,meta in pairs(inv.list()) do
local slotItem=inv.getItem(slot)
if slotItem and slotItem.consume then
item=slotItem
cachedSlot=slot
break
end
end
end
if item then
item.consume()
end
data=modules.getMetaOwner()
end
end
sleep(feederInterval)
end
end,
function()
while true do
local success,_=pcall(modules.getInventory)
if not success then
shell.run("reboot")
end
sleep(10)
end
end
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment