Spectrus
07-09-2013, 08:01 AM
Modules
I would like to preface this tutorial with a warning that some level of understanding of Lua is recommended to fully understand the module system.
What are modules?
Let's start with a little back story. In the early days of Xenobot, the only way to repeatedly do something was through loops. These were fine, but you could only have one infinite loop running at a time. People would seperate a whole ton of different scripts, each with one loop, making organization naught but wishful thinking. Another issue was that people were trying to append an infinite loop to a Lua file that was handling label events. The loop would block the event handler from catching the event. To counter this, another event was added (TIMER_TICK). The purpose of this was to allow for repeated actions while not blocking other portions of the script (i.e. label events). Syntax decided to expand on that by making modules. Modules are a feature implemented in to Xenobot to allow repeated actions while also allowing other things to happen within the same Lua file.
What do they look like?
The module system is fairly easy. All you need to do is create a variable to control it, like you would with any other object.
local newModule = Module.New('module1', moduleFunction)
Before we talk about what you can do with this module variable, let's talk about the parameters the Module.New constructor takes.
The first parameter is a name to associate with your module. This is mostly important if you are not going to tie the module to a specific variable. More on that later.
The second paramter is a function that you would like to have repeated.
But wait! There is a third optional parameter that designates whether you would like the module to be active or inactive on creation! It accepts a boolean value, true meaning active and false meaning inactive. The default is true (active).
local newModule = Module.new('module1', moduleFunction, false)
What can you do with modules?
Lots! Once you've created a module, you can control it using the member functions Module:Start(), Module:Stop(), Module:Delay(), and others.
Another neat thing is that having the ability to use static calls (and having a name associated with each module), you don't even have to tie the module to a specific variable. For instance:
Module.New('module1', moduleFunction)
Module.Stop('module1')
Even further than this, you don't need to declare the function to call outside of the module constructor. You can use what is called an anonymous function (one that has no name to be called upon). That looks like this:
Module.New('module1', function()
-- code to execute
end)
An important note is that in order to utilize the Module:Delay() function, you need to pass the module object to the function that you are calling. The code shows it best. (PS: Delays must be a multiple of 200, reason being that the TIMER_TICK event only fires every 200ms.)
Module.New('module1', function(moduleObject)
moduleObject:Delay(200)
end)
How do they work?
Okay, time for the fun part. Within Xenobot there is a concept called events. Basically, they are just things that happen in the bot. We have a Lua function that can listen for these events and call a function when they occur. Currently, there is only 2 events available to handle in Lua (WALKER_SELECTLABEL and TIMER_TICK). WALKER_SELECTLABEL obviously fires whenever the walker hits a label in the waypoint list. TIMER_TICK is an event that fires every 200ms. Modules simply expand off that. Every time a module is created, it is added to a list within a TIMER_TICK event listener within XenoLuaLib (the native Lua library for Xenobot). Every time that event listener triggers, the corresponding function executes, which runs through the list of modules and executes each function associated with the module. Here's a basic code representation of how it works:
local moduleList = {moduleFunction1, moduleFunction2, moduleFunction3}
function onTickEvent()
for _, func in ipairs(moduleList) do
func()
end
end
registerEventListener(TIMER_TICK, 'onTickEvent')
Questions?
Please ask away!
I would like to preface this tutorial with a warning that some level of understanding of Lua is recommended to fully understand the module system.
What are modules?
Let's start with a little back story. In the early days of Xenobot, the only way to repeatedly do something was through loops. These were fine, but you could only have one infinite loop running at a time. People would seperate a whole ton of different scripts, each with one loop, making organization naught but wishful thinking. Another issue was that people were trying to append an infinite loop to a Lua file that was handling label events. The loop would block the event handler from catching the event. To counter this, another event was added (TIMER_TICK). The purpose of this was to allow for repeated actions while not blocking other portions of the script (i.e. label events). Syntax decided to expand on that by making modules. Modules are a feature implemented in to Xenobot to allow repeated actions while also allowing other things to happen within the same Lua file.
What do they look like?
The module system is fairly easy. All you need to do is create a variable to control it, like you would with any other object.
local newModule = Module.New('module1', moduleFunction)
Before we talk about what you can do with this module variable, let's talk about the parameters the Module.New constructor takes.
The first parameter is a name to associate with your module. This is mostly important if you are not going to tie the module to a specific variable. More on that later.
The second paramter is a function that you would like to have repeated.
But wait! There is a third optional parameter that designates whether you would like the module to be active or inactive on creation! It accepts a boolean value, true meaning active and false meaning inactive. The default is true (active).
local newModule = Module.new('module1', moduleFunction, false)
What can you do with modules?
Lots! Once you've created a module, you can control it using the member functions Module:Start(), Module:Stop(), Module:Delay(), and others.
Another neat thing is that having the ability to use static calls (and having a name associated with each module), you don't even have to tie the module to a specific variable. For instance:
Module.New('module1', moduleFunction)
Module.Stop('module1')
Even further than this, you don't need to declare the function to call outside of the module constructor. You can use what is called an anonymous function (one that has no name to be called upon). That looks like this:
Module.New('module1', function()
-- code to execute
end)
An important note is that in order to utilize the Module:Delay() function, you need to pass the module object to the function that you are calling. The code shows it best. (PS: Delays must be a multiple of 200, reason being that the TIMER_TICK event only fires every 200ms.)
Module.New('module1', function(moduleObject)
moduleObject:Delay(200)
end)
How do they work?
Okay, time for the fun part. Within Xenobot there is a concept called events. Basically, they are just things that happen in the bot. We have a Lua function that can listen for these events and call a function when they occur. Currently, there is only 2 events available to handle in Lua (WALKER_SELECTLABEL and TIMER_TICK). WALKER_SELECTLABEL obviously fires whenever the walker hits a label in the waypoint list. TIMER_TICK is an event that fires every 200ms. Modules simply expand off that. Every time a module is created, it is added to a list within a TIMER_TICK event listener within XenoLuaLib (the native Lua library for Xenobot). Every time that event listener triggers, the corresponding function executes, which runs through the list of modules and executes each function associated with the module. Here's a basic code representation of how it works:
local moduleList = {moduleFunction1, moduleFunction2, moduleFunction3}
function onTickEvent()
for _, func in ipairs(moduleList) do
func()
end
end
registerEventListener(TIMER_TICK, 'onTickEvent')
Questions?
Please ask away!