If I call .list() or .size() on a chest in a coroutine it seems to blackhole that coroutine. I am new to using coroutines and I do not know enough to troubleshoot.
If I call the function processChests() as a function, it works as I would expect. Setup as a coroutine, it errors out on the first function I use chest.
I believe it errors out on line 299 where I call chest[c].list()[slot]
I have setup the peripherals as objects and then call the functions from plethora on those objects.
Thank you in advance
function processChests ()
while true do
print("processing chests")
for c=1,#chest do
print("chest: "..c)
for slot = 1,chest[c].size() do
print("slot: "..slot)
--only look at slots that have something
if chest[c].list()[slot] then
print(chest[c].list()[slot].name)
if pulverizerItems[chest[c].list()[slot].name] then
chest[c].pushItems(pulverizer[1].address, slot, 64, 1)
print("pulverize this")
elseif chest[c].list()[slot].name == "thermalfoundation:material" then
if smeltItems[chest[c].getItemMeta(slot).rawName] then
chest[c].pushItems(furnace[1].address, slot, 64, 1)
print("smelt this")
end
elseif hasDrawer(chest[c].list()[slot].name) then
print("moving to drawer: "..chest[c].list()[slot].name)
chest[c].pushItems(hasDrawer(chest[c].list()[slot].name), slot, 64, 1)
print("drawer this")
end
end
end
end
coroutine.yield()
end
end
script
[attach name=ae.txt type=text/plain]91[/attach].
Marc
I edited my processChests() function to
function processChests ()
while true do
print("processing chests")
for c=1,#chest do
print("chest: "..c)
for slot = 1,54 do
if slot == 1 then
write("slots: ")
end
write(" "..slot..",")
end
coroutine.yield()
end
end
end
This code has the behavior that I was anticipating for previously, but obviously does not actually do the list() function or push or pull items.
I understand that many functions will call yield so that my coroutine may yield before it got to my explicit coroutine.yield(), but if this was the case, would it not eventually get to my yield, because it is called to resume in the while loop.
Sorry if I end up rehashing some things you already know, but felt it was easiest to start from the top:
Every time you need to interact with the Minecraft world (such as a turtle digging a block or, as is the case here, listing items in a chest), we basically need to wait until the next Minecraft tick before we can do anything. This means that some functions (such as .list or .pushItems) have a ~0.05 second delay every time you call them.
As you end up calling list() 7 times each loop iteration, that's going to end up being about 0.35 seconds of delay for each iteration! You can avoid all of that by doing one list outside the loop - pretty similar to your second code snippet:
for c = 1, #chest do
local contents = chest[c].list()
for slot, item in ipairs(contents) do -- using ipairs means that empty slots are skipped
if pulverizerItems[item.name] then
chest[c].pushItems(pulverizer[1].address, slot, 64, 1)
end
-- etc
end
end
Note that you'll still end up with some delay each iteration, as pushItems will also pause by a tick. If you're feeling rather adventurous, you could do something with parallel.waitForAll (https://wiki.computercraft.cc/Parallel.waitForAll), which effectively allows you to run another bit of code if the first one is paused:
for c = 1, #chest do
local contents = chest[c].list()
local tasks = {}
for slot, item in ipairs(contents) do -- using ipairs means that empty slots are skipped
table.insert(tasks, function() -- Build up a list of functions to be done in parallel
if pulverizerItems[item.name] then
chest[c].pushItems(pulverizer[1].address, slot, 64, 1)
end
-- etc
end)
end
-- Run all the functions in one go - this should only take 0.05-0.10s, rather than 2 or 3.
if #tasks > 0 then parallel.waitForAll(table.unpack(tasks)) end
end
I changed the list() to be outside the loop, that is a much more efficient way to do it. This still does not fix it. The coroutine still seems to blackhole after any .list() or .size(). Even if I do just a print(chest[1].size())
function processChests ()
while true do
print("processing chests")
for c=1,#chest do
print("chest: "..c)
print(chest[1].size()) -- hangs here
local contents = chest[c].list()
for slot, item in ipairs(contents) do
print("slot: "..slot)
if pulverizerItems[item.name] then
chest[c].pushItems(pulverizer[1].address, slot, 64, 1)
print("pulverize this")
elseif item.name == "thermalfoundation:material" then
if smeltItems[item.rawName] then
chest[c].pushItems(furnace[1].address, slot, 64, 1)
print("smelt this")
end
elseif hasDrawer(item.name) then
print("moving to drawer: "..item.name)
chest[c].pushItems(hasDrawer(item.name), slot, 64, 1)
print("drawer this")
end
end
end
coroutine.yield()
end
end
on a side note, I just wanted to thank you for being so awesome.
I say blackhole, but what I mean is that I can look at coroutine.status and it says suspended, when I do a coroutine.resume, it replies true, but does not seem to actually resume.
Did you see any reason why it shouldn't work? albeit slow and inefficient?
Quote from: mmance on Dec 20, 2019, 08:22 PMI say blackhole, but what I mean is that I can look at coroutine.status and it says suspended, when I do a coroutine.resume, it replies true, but does not seem to actually resume.
Oooooh, are you running this code within your own coroutine manager? Can you post the code of that too?
I am just using the coroutine api. The whole code is posted in the first post as an attachment.
I was just curious where you were calling coroutine.resume? You shouldn't normally need to do that.
I am calling it in my main program loop. I expected that each time it was called, it would process a single chest and then yield to main.
It could be a fault in my understanding of how to use them.
Ohh i see what you are doing. You don't seem to understand how coroutines work or just don't realize that list() causes yield.
Every time you call list() it internally calls coroutine.yield("plethora_task") and is awaiting the event that signified the said task is complete. In your case you are discarding returns from coroutine.resume and using sleep() later which discards all events while sleeping. In effect you are discarding said "plethora_task" event in the sleep and resuming list with empty event so list() never know when it can return.
I would suggest looking how monitor and multishell programs work if you want to understand coroutines.
thank you for that, that gives me something to go on.
You approach with using just resume and yeld without event would have worked perfectly if you didn't need to call any functions that interact with world (like turtle movement/inspect , most of plethora chest interactions ect). IF it was function without any function that yeld internally (like pure calculation) it would work without issues way you wrote it. Sadly you are trying to interact with world so you do need to react to world events.
that helps a lot. I am so new to this that I was having trouble on where to start.
Oh, sorry - my brain entirely missed the download link in the OP. In addition to what Wojbie says, you need to be careful, as clearMachineOutput and processStrongbox also will yield, which means they throw away the plethora_task events that processChests needs.
The easiest thing to do here is probably just run the three in parallel:
-- Helper function which runs fn forever.
local function forever(fn)
return function()
while true do
fn()
sleep(2)
end
end
end
-- Run all three in parallel
parallel.waitForAll(processChests, forever(clearMachineOutput), forever(processStrongbox))