Any and all help with this is immensely appreciated, I've also included the process diagram below.
http://s24.postimg.org/oac2n66tx/Perfect_API_Page_1.jpg
That won't work in CraftOS. You'd need to create your own OS to add this functionality.
Er, could you not override os.pullEvent() so that it acts as a coroutine manager, in addition to its normal functionality?
Although I guess I'd have to learn how to force CraftOS to yield….. : /
--[[file as coroutine]]
while true do
print('coroutine is live')
coroutine.yield()
end
>lua
lua>parallel.waitForAny(os.loadAPI('file'),os.run({},"/rom/programs/shell"))
coroutine live
CraftOS 1.7
>[Enter]
>[Enter]
>exit
coroutine live --Presses [Enter]
coroutine live --Presses [Enter]
coroutine live --Presses [Enter]
coroutine live --Presses [Enter]
coroutine live --Presses [Enter]
parallel.waitForAny(function() os.loadAPI('file') end, function() os.run({},"/rom/programs/shell") end)
Er, could you not override os.pullEvent() so that it acts as a coroutine manager, in addition to its normal functionality?
parallel.waitForAny() expects you to pass it at least two function pointers. If you try to execute the functions yourself, than you'll instead end up passing the parallel API whatever those functions return. Your code isn't even managing to start parallel.waitForAny() - it's instead busy trying to resolve the arguments you wish to pass to it.
Now if you wrapped those calls inside function declarations, like so, then it'd do something closer to what you're wanting:parallel.waitForAny(function() os.loadAPI('file') end, function() os.run({},"/rom/programs/shell") end)
It's worth pointing out that the technique I initially suggested isn't simple coding. You won't be able to use the parallel API to pull it off; you'd need to understand how that API works so that you could devise your own coroutine manager.
If you're happy running a second shell alongside your code (which is what the above line does), then by all means stick with that.
-- The function we're going to run alongside everything else:
-- (Just an example of what you might use)
local function activeCode()
local counted = 0
repeat
local x, y = term.getCursorPos()
local xSize, ySize = term.getSize()
term.setCursorPos(1, ySize)
term.write("Events counted: "..counted.." (F12 to kill)")
term.setCursorPos(x, y)
local event, par = os.pullEvent()
counted = counted + 1
until event == "key" and par == keys.f12
end
local myCoroutine, oldCoroutineYield, hackySystem, myCoroutineFilter = coroutine.create(activeCode), coroutine.yield, false
coroutine.yield = function(filter)
if hackySystem then
return oldCoroutineYield(filter)
else
local myEvent, ok
hackySystem = true
repeat
myEvent = {oldCoroutineYield()}
if coroutine.status(myCoroutine) ~= "dead" and (myEvent[1] == myCoroutineFilter or myEvent[1] == "terminate" or not myCoroutineFilter) then
ok, myCoroutineFilter = coroutine.resume(myCoroutine, unpack(myEvent))
end
until myEvent[1] == filter or myEvent[1] == "terminate" or not filter
hackySystem = false
if coroutine.status(myCoroutine) == "dead" then coroutine.yield = oldCoroutineYield end
return unpack(myEvent)
end
end
function activeCode()
msgBuffer = {}
while true do
local e = {os.pullEvent()}
if e and e[2] == "modem_message" then
msgBuffer[#msgBuffer+1] = {e[6],e[3]}
end
os.pullEventRaw()
end
end
--Backup pullEventRaw and create our internal coroutine
local pullEventRaw_Backup = os.pullEventRaw
local coActive = coroutine.create(activeCode)
--Override os.pullEventRaw()
function os.pullEventRaw(sFilter)
while true do
local event = {pullEventRaw_Backup()}
--Define internal coroutines to check for
if coroutine.status(coActive) == "suspended" then
coroutine.resume(coActive, unpack(event))
end
--Return any events
if sFilter == event[1] or not sFilter then
return unpack(event)
end
end
end
My code doesn't actually fail to handle the filter - it just doesn't need to save it. See if you can follow my logic here:
*My os.pullEventRaw pulls events without the filter and then waits until it finds an appropriate one
*When calling coroutine.resume, the stuff I pass is going to be passed to another "instance" of the same function, which, as I said, doesn't pass anything back anyway.
If you're talking about my code, the mechanism for preventing duplicates should be quite obvious to you. At least, I can't think of a weak point.
Your code does prevent duplication, but doesn't handle terminate events correctly–these should bypass the filtering.
My code doesn't actually fail to handle the filter - it just doesn't need to save it. See if you can follow my logic here:
*My os.pullEventRaw pulls events without the filter and then waits until it finds an appropriate one
*When calling coroutine.resume, the stuff I pass is going to be passed to another "instance" of the same function, which, as I said, doesn't pass anything back anyway.
Er, yes, it does need to save it. See, when the function you build your coFoo() coroutine out of - foo() - yields, it passes back whatever parameter was handed to coroutine.yield() (in your case, the string "modem_message"). It expects this to mean it'll only be resumed when there's an event of that type at the front of the queue.
So what happens if you resume it with a different event type? Well, if the rest of the code in foo() is rigged to assume it'll only be resumed with "modem_message" events (which would be quite reasonable), odds are it'll crash messily, yes?
os.pullEvent( "message" )
function os.pullEventRaw(sFilter)
while true do
local event = {pullEventRaw_Backup()}
--Define internal coroutines to check for
if coroutine.status(coActive) == "suspended" then
coroutine.resume(coActive, unpack(event))
end
--Return any events
if sFilter == event[1] or not sFilter then
return unpack(event)
end
end
end
…which calls the old os.pullEventRaw without any parameters. Therefor, nothing will ever be passed by coroutine.yield, short of the user calling coroutine.yield directly themselves.
I'm not able to fix the duplicating events - any sort of coroutine manager (even parallel) running somewhere will screw it up - because os.pullEventRaw will be called multiple times per event. I really don't know how I'd figure out if the function is being called in some sort of coroutine manager, if it's possible at all.