Log in

View Full Version : [Tutorial] Module Tutorial



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!

xiaospike
07-09-2013, 08:25 AM
Do you like pie? :p

Blanz420
07-09-2013, 08:28 AM
Great tutorial, very useful and very simple to understand!

Spectrus
07-09-2013, 08:29 AM
Do you like pie? :p
Yeah it's not bad.


Great tutorial, very useful and very simple to understand!
Glad I could help. No one seems to use modules, and they are great.

xiaospike
07-09-2013, 08:30 AM
Goat pie? :)

Nano
07-12-2013, 11:33 PM
First of all THANK YOU!! Great tutorial!
I only have one question: Can I have more than 1 module running in the same script? I mean, does a module work like a thread in Java?

Thank you so much from now,
Nano

Nano
07-13-2013, 12:41 AM
Well I figured it out myself heheh.. Thank you so much anyways... For the ones who were asking the same or want to see two modules working at the same time, test this code:


local text_a = {"Hola", "Como", "Estas", "Tu?"}
local text_b = {"Hello", "How", "Are", "You?"}

local text_a_hud = HUD.New(10, 30, "Text A", 166, 244, 16) -- Handled by writeRandomTextA
local text_b_hud = HUD.New(10, 45, "Text B", 47, 218, 244) -- Handled by writeRandomTextB

Module.New("writeRandomTextA", function()

text_a_hud:SetText(text_a[math.random(1, 4)])

end, true)

Module.New("writeRandomTextB", function()

text_b_hud:SetText(text_b[math.random(1, 4)])

end, true)


This code creates 2 HUDs showing 4 random texts each. They change constantly, which clearly shows the TIMER_TICK event in action.

Good luck,
Nano

Spectrus
07-16-2013, 04:36 AM
First of all THANK YOU!! Great tutorial!
I only have one question: Can I have more than 1 module running in the same script? I mean, does a module work like a thread in Java?

Thank you so much from now,
Nano


Well I figured it out myself heheh.. Thank you so much anyways... For the ones who were asking the same or want to see two modules working at the same time, test this code:


local text_a = {"Hola", "Como", "Estas", "Tu?"}
local text_b = {"Hello", "How", "Are", "You?"}

local text_a_hud = HUD.New(10, 30, "Text A", 166, 244, 16) -- Handled by writeRandomTextA
local text_b_hud = HUD.New(10, 45, "Text B", 47, 218, 244) -- Handled by writeRandomTextB

Module.New("writeRandomTextA", function()

text_a_hud:SetText(text_a[math.random(1, 4)])

end, true)

Module.New("writeRandomTextB", function()

text_b_hud:SetText(text_b[math.random(1, 4)])

end, true)


This code creates 2 HUDs showing 4 random texts each. They change constantly, which clearly shows the TIMER_TICK event in action.

Good luck,
Nano

Sorry for late response!

They aren't quite the same as 'threads' in the sense that they do not run simultaneously. They run consecutively, but assuming you don't call any waits, they run so quickly it's not noticeable. Within the TIMER_TICK event handler inside the native lib, it runs through an array of module functions and executes them one at a time. Read the How do they work? section for a little bit more insight (or if you want, look in XenoLuaLib.lua!)

Hendy
07-17-2013, 12:52 AM
Yay for module guide!

Nano
07-23-2013, 11:22 PM
Sorry for late response!

They aren't quite the same as 'threads' in the sense that they do not run simultaneously. They run consecutively, but assuming you don't call any waits, they run so quickly it's not noticeable. Within the TIMER_TICK event handler inside the native lib, it runs through an array of module functions and executes them one at a time. Read the How do they work? section for a little bit more insight (or if you want, look in XenoLuaLib.lua!)

Oh! Now that I read the code of the native library, I realized it, that you very much again! Great tutorial :)

Tripkip
07-26-2013, 02:30 PM
So would this TIMER_TICK be more suitable for Making things such as SSA equiper for when below X Hp? A the refresh rate is quite fast?
Cuz im Looking for a script like that :P

pixie_frigo
08-28-2013, 02:07 PM
Tripkip, modules run every 200ms :)
So I guess if you want a hyper fast script while true is faster but I don't see the point in anything faster then 200 ms

Tripkip
08-28-2013, 02:26 PM
Tripkip, modules run every 200ms :)
So I guess if you want a hyper fast script while true is faster but I don't see the point in anything faster then 200 ms

Kom nou is online op hiberna of op skype betonblok