Since both coroutines and parallel are just fast switching mechanisms, this means the turtle is still moving and eating my precious events.
First you need to understand that each ComputerCraft system runs its code within a coroutine - one single Lua VM handles every computer / turtle within the one Minecraft world.
When you call os.pullEvent(), really you're causing your current coroutine to yield; more specifically, it's a wrapper for coroutine.yield(), and it calls that function for you. ComputerCraft resumes that coroutine when something happens - we call the data passed in at the time of resumption "an event".
An "event eater" is a function that yields over and over until resumed with a certain event. If it's resumed with an event that doesn't concern it, it ignores it and simply yields again. For example, turtle.forward() yields until resumed with a certain turtle_response event - if it's resumed with a rednet_message event before that time, you won't have an opportunity to act on it before the forward function essentially throws it away. Under normal circumstances, you can't switch to a rednet.receive() call while a turtle.forward() call is executing.
When you use the parallel API to run multiple functions in separate coroutines (running
within the coroutine you started off with), any events your main coroutine is resumed with are then passed on to each of the child coroutines. If one of the child coroutines calls an "event eater" function (eg sleep(), turtle.forward(), whatever), this will not prevent the parent from resuming the
other child coroutine with a copy of the same event data.
So, if you call turtle movement functions within one function, and call rednet-based functions within another, the parallel API can be used to run those functions within separate coroutines - each gets resumed with all event data they request, and you
can switch from one to the other while either turtle movement calls or the rednet message receiver are yielding within each.
Spoiler
local commands = {}
local function getMessages()
while true do
local senderID, message = rednet.receive()
if senderID == whatever then
commands[#commands + 1] = message
end
end
end
local function doWork()
while true do
if #commands > 0 then
-- Act on commands[1]
-- Make the turtle move around or whatever
table.remove(commands, 1) -- Remove first entry in table, next entry up will be pulled down into first index
else
os.pullEvent("rednet_receive") -- Yield until something might be added to the command list
end
end
end
parallel.waitForAny(getMessages, doWork)
Is there a list of event eating call somewhere?
The rule is that any function which
waits for
anything is yielding in order to do it, and will therefore pull and discard all events until it gets the one which signals what it's waiting for is ready.
For example, turtle movements take time (and wait for turtle_response events which confirm/deny whether the movements completed successfully), sleeping takes time (and waits for a timer event signalling that the duration is up), waiting for a rednet message may potentially take a lot of time (and waits for either a rednet_message OR a timer event)…
Some peripherals from third-party mods also trigger yields when you call their functions, but the above three are the ones most ComputerCraft coders are likely to run into.