AddOn programming introduction
This tutorial describes how to write a very simple and very basic AddOn. As it's tradition with almost all programing languages, it'll be a "Hello, World!" AddOn.
Note: Writing an AddOn is an advanced task. You need to be able to work with your computer. This especially includes:
- Know what operating system you're using (i.e. "Windows" or "Mac OS X").
- Know how to open a folder on your computer (either with the Windows Explorer on Windows or the Finder on MacOSX).
- Know how to generally use a text editor on your computer and save text files (you've written with this editor) to arbitrary folders.
- Know what a file and a folder (a.k.a directory) is.
- Know what something like "C:\Program Files\World of Warcraft\Patch.html" means (location of a file or folder).
- 1 Preparation
- 2 The new AddOn
- 3 Review
- 4 Pure Lua implementation
Writing an AddOn requires two pieces of software installed on your computer:
- World of Warcraft
- A text editor
A text editor is used to edit plain text files (hence the name). They need to be distinguished from word processors. Word processors allow text formatting (such as making text bold or italics). Thus they don't save plain text files but document files instead. On Windows, "Notepad" is a (very limited) text editor, whereas "Wordpad" and especially "Microsoft Word" are word-processor. You may use "Notepad", but you can't use "Wordpad" or "Microsoft Word".
There are dozens of free text editors out there. You will want to use one that has Syntax Highlighting. Here are some recommendations.
- On Windows: Notepad++ (freeware; highly recommended)
- On Mac: TextWrangler
- On Linux: Kate is shipped by default with KDE, while gedit is shipped with Gnome. Both of them have Lua syntax highlighting].
Note: You can find more lua editors at the Lua editors overview page. However, some of them may be more than what we need for this tutorial. So the recommendations above only contain basic editors.
Locate the AddOns folder
All AddOns lives in a very specific folder called AddOns. This folder is located here:
where %WorldOfWarcraftFolder% is usually the location where World of Warcraft is installed on your computer. In most cases the complete path looks like this:
- On Windows:
- either: C:\Program Files\World of Warcraft\Interface\AddOns
- or: C:\users\public\games\World of Warcraft\Interface\AddOns (since Windows Vista)
- On Mac: /Applications/World of Warcraft/Interface/AddOns
A note on Windows Vista and later: The AddOns folder may be located at the second path on Windows Vista and later (e.g. Windows 7). Basically this happens when the user has no administrator rights.
The new AddOn
As described above, all AddOns live in a very specific folder called AddOns. Each AddOn has its own directory under the AddOns folder.
Now go ahead and do these steps:
- Create a directory for your AddOn called HelloWorld
- Create three empty text files named: HelloWorld.toc, HelloWorld.lua, HelloWorld.xml
Note that the only difference in the three file names is the suffix. These denote, in order:
- the Table of Contents file (.toc)
- the Lua code file (.lua)
- the XML user interface visual elements file (.xml)
Important: The name of your AddOn directory and the name on the .toc file must match.
Important 2: If you add new files (e.g. lua or xml files) to your AddOn while WoW is running, you need to restart WoW. It's not sufficient to just reload the UI. Changing existing files, however, just requires a reload of the UI.
The next steps are to fill these three text files with some content. This is what the text editor is used for. The content of each file is described in the next sections.
The .toc or Table of Contents
This file tells WoW about your AddOn: what files to load and what order to load them in. Later you will want to have a look at the TOC format page for all of the gory details about what you can put into this file. For now we are just using some basic stuff.
Using your trusted text file editor, place the following into the HelloWorld.toc file:
## Interface: 70100 ## Title: Hello World! ## Notes: My first AddOn ## Version: 1.0.0 HelloWorld.lua HelloWorld.xml
This content should be pretty self-explanatory (except for the first line; see below):
- The lines starting with ## are called ".toc tags" and provide basic information about the AddOn.
- The other two lines (not starting with ##) tell WoW which files belong to the AddOn (here HelloWorld.lua and HelloWorld.xml).
- Lines starting with # (only one hash; not contained in the example above) are considered comments and are ignored by WoW.
So, starting from the first line we are saying:
- The compatible UI version for this addon is 70100
- The title of the addon to be displayed in game is "Hello World!"
- The description of the addon to be displayed in game are the notes
- The current version of the addon
- HelloWorld.lua file will be loaded.
- HelloWorld.xml file will be loaded.
A few notes on the first line:
## Interface: 70100
By the time you try to follow this tutorial, that value will probably have changed and you will need to put in the current value. If you've got WoW running, you can find out this number by running the following command:
/run print((select(4, GetBuildInfo())))
If not, may look into the .toc files of some other AddOns you've installed or have a look at Getting the current interface number.
What is this number? It's the user interface (UI) version for the AddOn. For instance, "70100" would correspond to WoW versions 7.1.x (where x is an arbitrary number). This number specifies which version of WoW your AddOn is compatible with; if it does not match the Blizzard UI number, your AddOn will be considered out of date, and will not be loaded unless the user checks the "Load out of date addons" checkbox before logging in.
For more details on stuff you can put in here, please visit the TOC format page.
The .lua or Lua code file
The .lua files are where the main "what to do" instructions for the AddOn reside. You will see a variety of terms for this "what to do" such as "logic", "executable code", or simply "code" (in most cases). Lua code does its thing in response to something that happens in the game. Things that happen in the game are called "events".
There are two basic kinds of events.
- The first kind of event is when something happens in the game. This might be somebody saying something, something happening to your character, another character's stats changing, etc. Nearly everything that happens in the game causes events.
- The second kind of event is when you do something to a UI Element (a UI Element is something on the screen - like a button - and is affectionately called a widget. We'll get to that more in the next section). This second kind of event might be clicking on something in your bags or button bar.
There is a technical difference between the two types of events, and we will discuss that as the tutorial progresses. For more details on the first kind of event see Events (API) and for the second see Widget handlers.
This discussion of events is extremely important because absolutely nothing happens in the game except in response to an event.
Important: Should you happen to write a piece of code that runs for an extended time (perhaps forever) absoultely nothing new will happen in the game. The game will freeze, nothing will move anymore, and the user will not be able click anything anymore. That would be classified as "not good".
So, how do you tell World of Warcraft that you are interested in a particular event? There are two ways: First, you can tell WoW which piece of code to run when a particular event happens. This is called registering your event. Second, you can tell the XML to run a piece of code when a UI Element is manipulated (such as clicking on it or moving your mouse over it). These pieces of code that run in response to events are called "functions" (or more precisly "event handlers").
Functions are groupings of code that accomplish a specific purpose. On one hand, there are numerous pre-defined functions provided by WoW. They're called "API functions" (API = Application Programming Interface). And on the other hand you can make your own user-defined functions.
While there are multiple ways to create functions in Lua, the easiest to understand looks like this:
[local] function function_name(<zero or more arguments>) -- code end
- The [local] is an optional keyword that limits the visibility of the function to a particular scope. Scope will be covered in more depths shortly.
- The function_name is simply a name you make up so you can reference your function from other places in your AddOn.
- The <zero or more arguments> are the way to pass information into the function. This is what gives functions their power. Each time you call the function, you can supply a different set of arguments and get different results based upon them.
- The ... code ... is where the work gets done in a function. Here is where you do calculations, comparisons, call other functions, etc to get the task of the function done.
- The end keyword simply marks the end of the definition of the function.
Note that this only defines the function. The function is not actually run until some other piece of code calls it.
Now to continue with our "Hello, World" code example, put the following into your HelloWorld.lua file and save it.
function HelloWorld(self) print("Hello World!"); end
You should understand everything in here by now. This function is named HelloWorld and it has zero arguments. The code part is simply the print("Hello World!"); portion. And it ends with end.
This is a fine piece of code, but by itself it's useless unless something calls this function. Onward to UI Elements (aka Widgets).
The .xml or XML visual elements file
"UI Elements", or "Widgets", are all of the tiny bits of graphics that make up the User Interface. WoW uses XML to layout everything that you see on the screen. Additionally, when things happen (called "events", remember?) to the widgets on the screen, event handlers (i.e. functions) can be called to perform whatever action you want. We will see shortly how we tell WoW which widgets we are interested in and which events we want to be handled by which event handler.
Blizzard XML format declared
For those of you who don't know: XML stands for "eXtensible Markup Language" and is a means of tagging content with identifiers. What identifiers (from here on called "tags") exist and how they're organized can be defined in something called an "XML Schema". In our case, we want to create XML documents that WoW will understand, so we will use the XML Schema provided by Blizzard for the Wow User Interface.
We declare that our document conforms to the Blizzard schema with the following bit of magic:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> <!-- the addon's functionality is defined in here --> </Ui>
The exact meaning of all of the above is beyond the scope of this tutorial, although if you are terribly curious you can read this Microsoft article on XML namespaces. For most addon developers it a magic formula that you always put in every.xml file you will create for the WoW user interface.
Blizzard defines the UI widget in UI.xsd. This file can be found at Interface/FrameXML/UI.xsd if you extracted the Blizzard interface, else wowprogramming.com maintains an online copy here. The XML user interface page has a good list under Widget Elements which will aid you until we get further along.
There are a few general notes that you need to know about concerning XML, particularly as it is used by WoW. The generalized format of a "tag" is:
<tagname attribute="attribute value" anotherattribute="anotherattribute value"></tagname>
A tag must have a tagname, and it may have zero or more attributes along with the attributes' associated values in double quotes. The tag is everything between the '<tagname' and the trailing '>'. The tag is closed by an "end tag" with the same name as the tag (i.e. '</tagname>'). Tagnames do not have spaces and are case sensitive. A valid tagname might be 'BackgroundWidgets', whereas 'backgroundwidgets' would not be valid.
Everything between the tag and the end tag is the content of the tag. Everything. Even other tags along with their content. In the case where there is no content to a tag, the tag can be shorted to <tagname /> instead of <tagname></tagname> though both versions are valid. A complete tag with no content looks like:
<tagname attribute="attribute value" anotherattribute="anotherattribute value"/>
Using the above piece of magic as an example, we can see that there is a tag with the name 'Ui' and that it has three attributes (the funny forth line is a part of the third attribute). Content is represented by the space between the end of the tag (the '>' on the fourth line) and the '</Ui>' end tag.
Now to continue with our "Hello, World" XML example, put the following text in your HelloWorld.xml:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> </Ui>
Now before we create the frame for our addon, we have to add a simple line of code that tells the WoW engine where to find our function in our .lua file. Notice this is a tag with no content, which gets a '/>' and no end tag. This is because this tag doesn't require any additional content (other than the name of the file).
WoW connects everything to a frame, even other frames. So, in order to create something that WoW will interact with, we create a frame:
<Frame name="HelloWorldFrame"> </Frame>
The tagname is 'Frame' and we have used the 'name' attribute and given the attribute the value of 'HelloWorldFrame'.
Our frame tag is included as content to the Ui tag and so goes between the start Ui tag and the end Ui tag. To help keep track of what is surrounding what, we indent the content with respect to the enclosing tags like this:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> <Script File="HelloWorld.lua"/> <Frame name="HelloWorldFrame"> </Frame> </Ui>
It is very important that you do not mix up the various end tags and indenting helps keep things straight. Notice that the 'Frame' and 'Script' tag are completely surrounded by the 'Ui' tag.
Inside the frame, one of the many things we can define are Scripts. Scripts are nothing more than small pieces of Lua code. Where we place the script determines when it will be invoked. Because Scripts live within a Frame we include the 'Scripts' tag inside the 'Frame' tag. Notice the difference, in the 'Scripts' tag, the 's' sets it apart from the 'Script' tag.
<Frame name="HelloWorldFrame"> <Scripts> </Scripts> </Frame>
The various widgets have several Events that can occur and if we want to declare a Widget Handler to process the event we include the event name under the Scripts tag of the widget we are interested in. Not every widget has the same set of events. In this example, we are interested in an event named 'OnLoad'. The OnLoad event happens when the widget is loaded into the UI. For this example, we want the OnLoad event to run the script named HelloWorld. This script was defined in the HelloWorld.lua as a function.
<Scripts> <OnLoad> HelloWorld(self); </OnLoad> </Scripts>
Take a look at the Widget handlers page for a list of widgets and the events you can write widget handlers for.
The complete HelloWorld.xml file should look like this:
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> <Script File="HelloWorld.lua"/> <Frame name="HelloWorldFrame"> <Scripts> <OnLoad> HelloWorld(self); </OnLoad> </Scripts> </Frame> </Ui>
There is an important thing you should note in the code above. The HelloWorld(); is the only piece which is NOT a tag or an attribute. It is important to note that content in a WoW .xml UI document is always a piece of code if it is not another set of tags and their associated attributes. The only valid place for a piece of code is under the tag for an event.
Having gotten this far, it is time to run your new AddOn.
Running your HelloWorld AddOn
You should now have a folder called "HelloWorld" in your "AddOns" folders, and in that folder there should be three files named HelloWorld.toc, HelloWorld.lua, and HelloWorld.xml. The contents of these three files should be exactly as listed above.
Now start World of Warcraft and log into your account, but don't select your character yet. Please click the red 'AddOns' button on the lower left of the character selection screen to see all of the AddOns WoW has detected. There will be one for every folder in your AddOns directory except for the AddOns starting with "Blizzard_".
You should see your new HelloWorld in this list. The name should be yellow, and the checkbox to the left should be checked.
If the name is Red and you see an Out of date message to the right, you probably didn't change the ## Interface: 40200 line in your HelloWorld.toc (as described above). Please review that section and make the appropriate change.
I do not recommend running your AddOns with the 'Load out of date AddOns' checkbox checked. That's asking for trouble as an AddOn that attempts to use old UI features can corrupt a new UI. Nearly every patch that changes the UI level has had problems with old AddOns that have not been updated to conform to the new UI standards.
If you don't see your new AddOn at all, make sure that you have placed the HelloWorld folder in the right folder (called "AddOns") and that the files inside the "HelloWorld" folder have the right names and contents.
A note for windows users: make sure that you don't accidentially save your files as "HelloWorld.toc.txt" (instead of "HelloWorld.toc") etc. There is an option in windows explorer will hide the .txt suffix.
Please note the case (upper-case vs. lower-case letters) of the names of your folder and files: While Windows is insensitive to case for folder and file names, the case may be important on a Mac. Also, inside the game itself, World of Warcraft is sensitive to the case for the names of its variables and filenames. Keep the case the same to avoid problems.
Now, you have a yellow "HelloWorld!" AddOn showing up in your AddOn list. Note the ! in the name. The name of the AddOn shown in this list is taken from the ## Title: Hello World! line in the HelloWorld.toc file. In the future, we will see how to change colors and languages.
If you move your mouse cursor over the HelloWorld name, you should see a tool-tip pop up with two lines in it. The first line is the same as the title, and the second line is taken from the ## Notes: My first AddOn line in the .toc file. This can also be customized for color and language.
Cancel out of the AddOns display and enter the world with any of your characters. Once your character loads, you should see a message in the default chat window that says Hello, World! .
You have created your first AddOn and have successfully run it. Now let's review a bit about what was accomplished.
The 'Hello World!' text is taken from the line in the HelloWorld.lua file that reads 'print("Hello World!");'. Wrapped around that is a function named print which is responsible for displaying the text in the default chat window.
The print function is inside a function we created called HelloWorld that had no parameters. Our function will do the same thing every time it is called.
You should then recall that the name of our function was placed in the HelloWorld.xml file as the action to be taken when the Onload event of the Scripts tag of the Frame we created. We placed the name of our function in this specific place because we wanted our function to be executed (run, called, processed) when our Frame was fully loaded.
World of Warcraft knew that it should create our Frame because we placed the name of the .xml file into the .toc file. The .toc file must have the same name as the AddOn's directory and is the first of the files in our AddOn that Blizzard processes.
Inside the .toc file is where we tell World of Warcraft about our AddOn (the ## statements) and what files that need to be loaded. Every line that does not start with a ## is a file to be processed by World of Warcraft. The order that the file names appear is important because World of Warcraft processes the file in order listed.
Knowing that, we place the .lua file before the .xml file because we want the function HelloWorld declared (or defined) before we try to call it in the .xml file.
Even though this is a trivial example of an AddOn , important concepts and information have been covered. Further pages in this tutorial will cover other areas and expand upon topics initially presented here.
Pure Lua implementation
Alternatively, Hello World can also simply be written without any use of the XML file
- As a single print statement
- In a function
local function HelloWorld() print("Hello World!") end HelloWorld()