Last active
July 9, 2020 22:42
-
-
Save object-Object/b74b42b5360d2190915047c17f5aa34b to your computer and use it in GitHub Desktop.
CC+Plethora wireless storage system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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