This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
exploder's profile picture

Event queue

Started by exploder, 07 December 2013 - 07:50 AM
exploder #1
Posted 07 December 2013 - 08:50 AM
Hello there.

I would like to ask a question: is there a way to queue event so I can use it after some loops and functions because I have a turtle that is mining and I need him to listen for rednet messages at the same time, so for example if the message is "test123" the turtle stops mining.

Computer code:

rednet.broadcast("test123")

Turtle code:

-- If I put os.pullEvent("rednet_message") here, it just stays at the spot and waits for the message.
for i=1,60 do
  turtle.digDown()
  turtle.down()
-- I need to check here if the message sent to turtle was test123 if it is, then stop.
end

I hope you will understand what I want to accomplish here because English is not my native language :P/>.
Edited on 07 December 2013 - 07:52 AM
TheOddByte #2
Posted 07 December 2013 - 09:04 AM
Well I think parallel will work for this or you could simply use a while loop instead with a timer

Here's how you can do it with a while loop using a timer

local i = 1
local timer = os.startTimer(.8) -- Starting the timer
while i < 61 do
	local evt, id, msg = os.pullEvent()
	if evt == "timer" then	-- Checking if the event that was pulled was the timer
		if id == timer then	-- Checking which timer it was
			turtle.digDown()
			turtle.down()
			timer = os.startTimer(.8) -- Restarting the timer
            i = i + 1
		end
	elseif evt == "rednet_message"
		-- Handle rednet message here
	end
end
The reason there is a timer is so the loop won't hang.
Edited on 07 December 2013 - 08:07 AM
Bomb Bloke #3
Posted 07 December 2013 - 04:58 PM
The timer isn't an option. The turtle takes time to move, and while it waits for the special event signifying those movements are complete, it pulls all other events that comes in and discards them. That means your own os.pullEvent() call has a fair chance of "missing" the rednet and timer events because the turtle functions already ate them.

Hence the parallel API wins out. Two functions running at once, each gets a copy of everything that runs through the event queue. This means that the turtle functions can run in one and won't affect your attempts to retrieve rednet messages in the other.

Eg:

rednet.open("right")

local function getMessages()
  local myMessage
  while true do
    myMessage = {rednet.receive()}
    if myMessage[2] == "test123" then break end
  end
end

local function descend()
  for i=1,60 do
    turtle.digDown()
    turtle.down()
  end
end

parallel.waitForAny(descend, getMessages)  -- Run the two functions at once until either finishes.

rednet.close()
theoriginalbit #4
Posted 07 December 2013 - 07:31 PM
The timer solution that Hellkid98 posted could however be implemented if you used the turtle.native calls and listened for the turtle_response event yourself… but definitely go with what Bomb Bloke was saying, its much simpler!
Molinko #5
Posted 08 December 2013 - 04:14 PM
The timer solution that Hellkid98 posted could however be implemented if you used the turtle.native calls and listened for the turtle_response event yourself… but definitely go with what Bomb Bloke was saying, its much simpler!

could you elaborate on this "turtle_response" event fur me. its this only exposed when you are using turtle.native? audio what is the difference between turtle and turtle.native
theoriginalbit #6
Posted 08 December 2013 - 05:01 PM
could you elaborate on this "turtle_response" event for me. its this only exposed when you are using turtle.native?
it is definitely not only exposed when using turtle.native, it actually occurs each time you invoke a turtle function, the reason that you never see it is because each time a non-native turtle function is invoked it will wait for that event, meaning that you never get to see it. Basically though a turtle_response event is a turtle notifying you that it has completed an action that you've told it to. Each time you invoke a turtle.native function it will return you a unique id; when a turtle_response event fires it will also provide you with an id. If these two ids match then that means the particular command has completed, however if the turtle_response event returns -1 as the id it means that the task you're getting it to do has failed.

code example

local currentId = turtle.native.forward()

while true do
  local event = {os.pullEvent()} --# we could do use a filter, os.pullEvent("turtle_response"), but we don't so you can see you can check for other events

  if event[1] == "turtle_response" then
	if event[2] == currentId then
	  return print("Our turtle task has completed!")
	elseif event[2] == -1 then
	  return print("Our turtle task has failed!")
	else
	  print("Unknown turtle task completion! This shouldn't happen!")
	end
  else
	print("Another event has happened that we don't need to respond to in this code")
  end
end

also what is the difference between turtle and turtle.native
turtle.native is the Java-side code that actually makes the turtle move and such. turtle is the Lua-side code that implements the wrapper for the turtle_response event (see snippet below)

relevant turtle api code

native = turtle.native or turtle

local function waitForResponse( _id )
  local event, responseID, success
  while event ~= "turtle_response" or responseID ~= _id do
	event, responseID, success = os.pullEvent( "turtle_response" )
  end
  return success
end

local function wrap( _sCommand )
  return function( ... )
	local id = native[_sCommand]( ... )
	if id == -1 then
	  return false
	end
	return waitForResponse( id )
  end
end

-- Wrap standard commands
local turtle = {}

for k,v in pairs( native ) do
  if type( k ) == "string" and type( v ) == "function" then
	if turtle[k] == nil then
	  turtle[k] = wrap( k )
	end
  end
end
Edited on 08 December 2013 - 04:01 PM
Molinko #7
Posted 08 December 2013 - 11:13 PM
Thank you Original Bit. That was some very handy info. Sorry for my horrible typing earlier, android swype can really suck sometimes..

If its not too much how is the native in term.native relevant or useful? Is there also a wait and response involved? Is this relevant to term.redirect()??
theoriginalbit #8
Posted 09 December 2013 - 02:33 AM
If its not too much how is the native in term.native relevant or useful? Is there also a wait and response involved? Is this relevant to term.redirect()??
Its the same deal again, term.native is the Java-side implementation, term is the Lua-side implementation. One of the reasons for this is to allow for the term.redirect. Basically what it does is instead of consistently invoking the same functions, it will invoke the ones that are on the top of the redirect stack (see code example 1 for relevant code from the term api). This allows you to redirect the terminal to other objects, such as monitors, and have the terminal calls on them (see code example 2).

Code Example 1

local redirectTarget = native
local tRedirectStack = {}

local function wrap( _sFunction )
  return function( ... )
	return redirectTarget[ _sFunction ]( ... )
  end
end


local term = {}

term.redirect = function( _object )
  if _object == nil or type( _object ) ~= "table" then
	error( "Invalid redirect object" )
  end
  for k,v in pairs( native ) do
	if type( k ) == "string" and type( v ) == "function" then
	  if type( _object[k] ) ~= "function" then
		_object[k] = function()
		  term.restore()
		  error( "Redirect object is missing method "..k..". Restoring.")
		end
	  end
	end
  end

  tRedirectStack[#tRedirectStack + 1] = redirectTarget
  redirectTarget = _object
end

for k,v in pairs( native ) do
  if type( k ) == "string" and type( v ) == "function" then
	if term[k] == nil then
	  term[k] = wrap( k )
	end
  end
end

Code Example 2

--# you should know the outcome of the following 3 lines
term.clear()
term.setCursorPos(1,1)
print("I print on the terminal!")

--# this is where term.redirect comes in
local monitor = peripheral.wrap("left")
term.redirect(monitor)
--# the following statements will now output to the monitor because of the above line
term.clear()
term.setCursorPos(1,1)
print("I print on the monitor!")

--# now if we use term.restore the monitor object is popped off the stack and now the term api prints back to the terminal
term.restore()
print("I am back to the terminal!")
Edited on 09 December 2013 - 01:34 AM
exploder #9
Posted 09 December 2013 - 04:25 PM
Got my turtle to do what I wanted, thanks everyone for posing and helping.