Jump to content




Event Basics


10 replies to this topic

#1 Engineer

  • Members
  • 1,378 posts
  • LocationThe Netherlands

Posted 10 August 2013 - 08:23 PM

Introduction
Hello dear community,
Today I'm writing a tutorial about the event system we can use in CC-Lua. I call the language CC-Lua, because normal plain Lua you install on your computer won't be compatible with a few function calls. For those who are not familair, CC stands for ComputerCraft.

So, what are events? Events are things you can trigger by clicking, hitting a key, scrolling your mousewheel and much more. The goal of this tutorial is to let you know how we can get the events, how we can use the events and why you want to use events.

For this tutorial you need to know what: Now, after this short introduction, lets start the tutorial!

Event Basics
So events are things that get triggered when something happens to the computer. For example, it could be your input, but also things like redstone could trigger an event. So almost anything that happens to the computer, can trigger an event. But this does not count for running code, actually, it can but we will get into that later.

To let our program know something is going to happen is using this function:
os.pullEvent()

This function is described on the wiki like so:Posted Image

Boy, that is a lot of information at once. Lets forget the target-event for now, I want to explain the very basics first.

If we simply put os.pullEvent() plain in our code, it will wait for something to happen and then continue. So you cannot immediately print something after it. That code will look like this:
os.pullEvent()
print( "Hey, something happened to this computer!" )

Now if we want the information that happens, we have to catch that event first. That is going to look like this:
local event = os.pullEvent()

Basically we are creating a variable that catches what the os.pullEvent() returns. Just like you in the image read:

Quote

os.pullEvent(target-event) returns the event and any parameters the event may have.

Wait a minute, it can return parameters too? That means that os.pullEvent() can return multiple values! Per event it differs how many values get returned, so we do the max, which is 5 by the default events ( I will get into custom events later ), because we want to catch everything.
Usually, something like this gets done, it could be totally different since it are variables!
local event, value1, value2, value3, value4, value5 = os.pullEvent()

So we catch this in order:
  • The event name
  • The 1st event-value that gets returned
  • The 2nd event-value that gets returned
  • The 3rd event-value that gets returned
  • The 4th event-value that gets returned
  • The 5th event-value that gets returned
To know what actually gets returned as first, second, third or fourth value, we can look that up on this page. A nice table is laid out for us on the bottom so we can see what kind of events happen regularly and what they return with them. They have their own packet so to say.

Now we can get into the argument os.pullEvent takes: string target-event (See the wiki image!)
This will say, that the argument is a string, so we need the quotes. Now what we can do, is pull only one event! So if you do not need an event that says that a peripheral gets attached, this is the solution. But there is one catch, you can only use that one type of event for those variables. So lets say we want the char event ( see the wiki page! ), we can simply do this:
local event, key = os.pullEvent( "char" )

We can actually name our arguments, because we know we are only to get the char event from this.

The point of this event system is, that you can do multiple stuff, without doing complicated things with coroutines (WARNING: This is advanced! Get into it when you're curious enough!).

We mainly use a while-loop to pull constantly events and process them. So, to create an infinite while-loop we do:
while true do

end

And do you remember that os.pullEvent() waits until something happened, or the target event gets hit? So does it here, it literally blocks the loop from looping until something happened.

Now, since we probably want to catch multiple events, it is going to be a plain os.pullEvent() with the catch variables. Like so:
while true do
  local event, value1, value2, value3, value4 = os.pullEvent()
end

At this point, we can process the events, because we know what event happens. You create an if-elseif-end structure, and by the way you do remember you can look up the events with their values, right?
This is going to be your basic structure:
while true do
  local event, value1, value2, value3, value4 = os.pullEvent()
  if event == "eventName" then

  elseif event == "otherEventName" then

  end
end

You actually replace 'eventName' and 'otherEventName' with actual event names you looked up, right? :P/>/>/>
Within that if, you can process those values to your wishes.

Now I want to notify you on something that might be usefull to you, if you hate those ugly variable names like value1 etc. We can put the os.pullEvent() in one table, and then use the table to get your values:
while true do
  local eventValues = { os.pullEvent() }
  if eventValues[1] == "eventName" then

  elseif eventValues[1] == "otherEventName" then

  end
end
I will not get deep into this, but it might usefull to you.

Okay, if you are still with me I will show you show some examples and explain the os.queueEvent function.
But first, the examples we can create with what we have learned today. Im going ahead and put the examples in a spoiler, since it will probably get long again. I dont want to over use the space this thread is already taking ;)/>/>
Examples:
Spoiler

Custom events
It is very simple to create custom events. The function you will use for that, as mentioned earlier, os.queueEvent(), but we need arguments.

Basically, the first argument is your eventname, and after that you pass variables you want to pass. The next time you are trying to os.pullEvent() it will show up!
Warning: functions like: read(), sleep() etc. empty the event stack and you will not be able to pull the event after that

So this is an example:
os.queueEvent( "testevent", 5 )
local event, value = os.pullEvent()
-- event -> testevent
-- value -> 5

Do whatever you need your own special event :) Oh, and by the way, you can simulate a keypress:
os.queueEvent( "key", 26 )

This probably wraps up this tutorial... for now.. :P

If you have any question please ask them! I will answer them A.S.A.P. and if they are usefull for other users I will put it in the tutorial self.

If I made any mistakes, please correct me! English is not my native language but I try my best :)

Thanks for reading,

- Engineer

#2 Bubba

    Use Code Tags!

  • Moderators
  • 1,142 posts
  • LocationRHIT

Posted 10 August 2013 - 08:53 PM

Looks good! One thing you may want to mention is os.queueEvent, but other than that this is a very good beginner's tutorial. You link anything that might need explaining and provide both explanation and code. Nicely done :)

Edit: Oh, and you might want to explain events as anything that computers are notified about rather than anything that the user triggers. The user can trigger events, but for example redstone is not. Just nitpicking here.

#3 Engineer

  • Members
  • 1,378 posts
  • LocationThe Netherlands

Posted 11 August 2013 - 12:09 AM

View PostBubba, on 10 August 2013 - 08:53 PM, said:

Looks good! One thing you may want to mention is os.queueEvent, but other than that this is a very good beginner's tutorial. You link anything that might need explaining and provide both explanation and code. Nicely done :)

Edit: Oh, and you might want to explain events as anything that computers are notified about rather than anything that the user triggers. The user can trigger events, but for example redstone is not. Just nitpicking here.
Thanks for the feedback! Actually, I was planning to do the os.queueEvent, but I decided to first wait for feedback. I actually mentioned somewhere something along the lines of custom events. I will write that up later.

I changed it, I hope it is better now :)

#4 svdragster

  • Members
  • 222 posts
  • LocationGermany

Posted 16 August 2013 - 12:26 PM

Nice tutorial!
I didn't really know what the queueEvent does or how it works. Thanks!

#5 Oompf

  • New Members
  • 2 posts

Posted 31 December 2013 - 06:21 AM

I didn't understand if multitasking is able to run code while a coroutine is waiting for a keypress (as i read the code you have to switch to the other "task" by command.

in this case it is not possible e.g. Count up a value and write to the screen until a key is pressed.

local function waitkeypress()
  local e
  while e = {os.pullEvent()} do
    if e[1] == "key" and e[2] == keys.enter then
      return true
    end
  end
end
local i = 0, waitc = coroutine.create(waitkeypress)
while coroutine.status(waitc) ~= "dead" do
  print(i)
  i = i + 1
end

would this work?

View PostEngineer, on 10 August 2013 - 08:23 PM, said:

...
Warning: functions like: read(), sleep() etc. empty the event stack and you will not be able to pull the event after that
...

is this because of these comands using the stack itself?

if i want to count up once a second by adding a sleep(1) to the loop, it might happen that the event itself will be deleted by the sleep?

#6 Engineer

  • Members
  • 1,378 posts
  • LocationThe Netherlands

Posted 01 January 2014 - 11:03 AM

View PostOompf, on 31 December 2013 - 06:21 AM, said:

I didn't understand if multitasking is able to run code while a coroutine is waiting for a keypress (as i read the code you have to switch to the other "task" by command.

in this case it is not possible e.g. Count up a value and write to the screen until a key is pressed.

local function waitkeypress()
  local e
  while e = {os.pullEvent()} do
	if e[1] == "key" and e[2] == keys.enter then
	  return true
	end
  end
end
local i = 0, waitc = coroutine.create(waitkeypress)
while coroutine.status(waitc) ~= "dead" do
  print(i)
  i = i + 1
end

would this work?

No, that wont really work. BUT, for information for os.pullEvent, I would refer to this tutorial: http://www.computerc...ics-coroutines/

View PostOompf, on 31 December 2013 - 06:21 AM, said:

is this because of these comands using the stack itself?
if i want to count up once a second by adding a sleep(1) to the loop, it might happen that the event itself will be deleted by the sleep?
Yeah, because if something gets called while sleeping, you really cant process it.
If you want to count up each second, you should use this:
local count = 0

local TIMER = os.startTimer(1)
while true do
	local e = {os.pullEvent()}
	if e[1] == "timer" and e[2] == TIMER then
		  TIMER = os.startTimer(1)
		  count = count + 1
	end
end

This way you can process each event that happens.

#7 ZombieTurtle

  • Members
  • 13 posts

Posted 13 February 2014 - 06:56 AM

This is really helpfull thank you :D

#8 skwerlman

  • Members
  • 163 posts
  • LocationPennsylvania

Posted 10 March 2014 - 10:54 AM

Is the event stack last-in-first-out or first-in-first-out?
EG:
if I did this
os.queueEvent("event1")
os.queueEvent("event2")
what would os.pullEvent() return?

#9 theoriginalbit

    Semi-Professional ComputerCrafter

  • Moderators
  • 7,332 posts
  • LocationAustralia

Posted 10 March 2014 - 10:56 AM

View Postskwerlman, on 10 March 2014 - 10:54 AM, said:

-snip-
It's an event queue, so its FIFO.

#10 skwerlman

  • Members
  • 163 posts
  • LocationPennsylvania

Posted 10 March 2014 - 10:57 AM

Thanks! And so fast, too!

#11 theoriginalbit

    Semi-Professional ComputerCrafter

  • Moderators
  • 7,332 posts
  • LocationAustralia

Posted 10 March 2014 - 10:59 AM

you're welcome :)





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users