UI Scripting Tutorial/Walkthrough
Lately there's been a rather... large... influx of players
into the WoW community, including myself, many of whom have some coding
experience and wish to test their skills and create UI AddOns for World of
Warcraft. As with any programming language and interface, there's a bit of a
learning curve, so hopefully this will help reduce that (and the headache of
digging through various resources for that perfect function) ;)
1. Preparing for the Plunge
a. Weapon of Choice
The first order of business is to get a general understanding of what’s going on
here. But in order to do that, it might be best if we armed ourselves with an
arsenal of tools to use throughout our coding (modding) saga.
I’m sure at some point we’ve all been on the search for the holy grail of
editors (or IDE’s as a slightly more specific term :P), which is often a rather
frustrating and long search. (Hell, I have yet to find my “perfect” editor for
many of the languages I code in). Anyway, since our scripting language is LUA,
we would probably do best with an editor that’s geared towards it. So here’s a
list of possibilities, choose well…
http://blua.sourceforge.net/
B:Lua – This looks like it is going to be our true holy grail right here. Emil
is cooking up a fully featured IDE for the single purpose of coding for
the World of Warcraft UI. Even better, it’s java, so regardless of what
operating system you use, you’re going to benefit from this application!
Unfortunately, however, he’s not quite done with his first version. So keep your
eye on this one, it’s going to make things a hell of a lot easier on us! So big
thanks in advance, Emil!
http://www.ideais.com.br/luaeclipse/
Lua Eclipse – here’s another java IDE to use. I haven’t used this particular
editor yet, so I can’t comment very much. It is based on the Eclipse platform,
which is an extremely feature-rich framework for any IDE, so I’m sure it is a
great editor to use. (might be a bit bulky, however)
http://editplus.com/
EditPlus – Here’s a great notepad replacement, and currently my LUA coding
application of choice. It’s got all the basic features you need, and even has a
syntax scheme for LUA code (http://www.editplus.com/files/lua2.zip).
However, there’s a 30 day evaluation period with EditPlus, and then you need to
pay for it.
Those are just three suggestions – and I think once B:Lua is released, there’s
not much of a choice left – I’m switching! :)
b. We Have Our Weapon, but What Shall We Target?
Once you have your editor, that’s only the beginning. We’re going to want a few
tools specific to WoW as well. The first of these is WinMPQ, which you can find
here:
http://shadowflare.gameproc.com/dwnload.html#WinMPQ
Grab the first set of files (you’ll probably need both of the runtime file packs
– it’s a visual basic 4 application). With this, you will be able to dig around
in the game’s various MPQ, or MoPaQ, files. MPQ’s are Blizzard’s proprietary
format to store game files (think of it as a glorified zip file). If you’re
interested in the nitty gritty, as well as the history behind MPQ’s, I suggest
you check out “Inside MoPaQ” (http://www.campaigncreations.org/starcraft/inside_mopaq/index.htm).
With WinMPQ, you can now extract the contents of the interface and patch MoPaQ’s,
(stored in the data folder in your WoW install) which contain everything you’ll
ever need (and more) for your World of Warcraft interface modding saga.
Interface.MPQ stores the base interface, and thus a majority of the interface
files that you can use as examples. Patch.MPQ stores the contents of *all* the
patches up to present, and basically is an override for all the base MPQ’s.
So, open up WinMPQ, as we’re going to pull out all the base interface code for
you to use as an example. Plus I’ll show you how to keep up-to-date with any
changes made by patches. So, with WinMPQ open, click on “open” and then select
Interface.MPQ (again, in the data directory of your WoW install) Scroll down a
ways, and you’ll start to see files in a FrameXML folder (there’s also a GlueXML
folder, but you really don’t need to worry about that – I’ll explain in a bit),
so select all the FrameXML files and extract (hit the button) them somewhere
outside of your WoW folder.
We’re going to do the same for Patch.MPQ, so open that up too. You’ll notice
that Patch.MPQ stores any files updated by our patches, and not just interface
files. No matter, we’re only interested in anything under Interface\FrameXML –
so grab all those and extract them to the same place as where you previously
extracted the FrameXML files from Interface.MPQ (older files will be
overwritten). So now you’ve got an up-to-date copy of FrameXML to base your code
off of and to use as a reference!
(as a side note, you might want to extract the music, all in mp3 format, to a
folder somewhere as it makes for some relaxing music to code to :P)
2. Target Acquired
Now that we’re all ready, it’s time to make your first AddOn!
But, I think first, you need to understand where files are located, and which
ones do what. So, let’s take a look at our World of Warcraft install. Inside it
are various folders, but the one we’re going to be mucking about in is the
Interface folder (create it if it doesn’t exist). Inside the Interface folder
are (or will be once you start modifying things) three folders:
FrameXML: This contains all the Blizzard-supplied interface code. The bulk of
what you interact with is stored here (though the art is stored elsewhere).
GlueXML: This contains all of the “out of game” interface, such as login, server
selection, character creation, etc. You really shouldn’t need to play around
with this, nor want to.
AddOns: This is where you come in! Every player-made module is placed in here.
Now, inside the AddOns folder, each module has its own folder and a table of
contents inside that.
3. Commence the jiggling!
a. Initial Setup
So we’re at the point where we’ve gotta do the obligatory Hello World. So start
off by making a folder called hello_world under your AddOns folder. Aka, you
need it to be placed here:
World of Warcraft/Interface/AddOns/hello_world
Inside this folder, create a file called hello_world.toc. This is your table of
contents, and subsequently where you specify what files that WoW should load. A
basic Table of Contents looks like this:
## Interface: 4114
## Title: Hello World
## Notes: The obligatory hello world script – WoW-style!
## OptionalDeps:
## Dependencies:
hello_world.xml
So this needs some explaining. The first line is a relatively new addition to
the UI coding scene. Basically, every time Blizzard puts out a new patch, the
“current” version number is going to change. If your script does not have the
latest version, it *will not* be loaded (It would be nice if we could specify
“version equal to or greater”). This is why whenever there’s a patch, all the
AddOns break.
Note that you can find the latest version by extracting the file: Interface\FrameXML\FrameXML.toc
from Patch.MPQ and opening it in your favorite editor.
I think Title and Notes are pretty self-explanatory. As for OptionalDeps, you
can list off any “optional dependencies” that your AddOn may have (you list off
other AddOns, separated by spaces). The same goes for Dependencies, except these
aren’t optional :P I believe, but I am not sure (I haven’t really tested it)
that your AddOn will *not* load if its dependencies don’t exist. In any case,
it’s a good idea to stick in any dependencies, optional or not, to help anyone
trying to read your code (including yourself :P).
Past the initial declarations, you place a list of xml files to be loaded *in
the order that they are written*, one file per line. Note you can also store
these in sub-folders to keep things a bit cleaner (for instance you could have
the line “core/hello_world.xml” if you wanted a core folder in your AddOn)
b. Adding Some Meat
Now for the fun part! Let’s start out with something pretty simple here, nothing
fancy. Create a new file called hello_world.xml (which you specified in the
table of contents), and open it up in your favorite editor. Stick this in it:
Unfortunately, I can't post the xml as it breaks the post - so you can find
the source here (check out the file hello_world.xml)
http://wow.nevir.net/tutorial/hello_world/
Oh dear, it just got a bit more complex… So, you can safely ignore all the junk
up top (the <Ui…. tag), but pay attention to the line: <Script file="hello_world.lua"/>.
This tells WoW to load the file, hello_world.lua, which is where the body of
your AddOn will reside.
Now… every part of the interface is contained within a “Frame” Here we have a
frame to simply handle any events our script should be aware of, but you also
stick all your buttons, windows, etc within frames too (more on this in a bit).
In our frame tag, we define a name – this *must* be a unique identifier for this
frame. It is recommended that you prefix the name with the name of your module,
followed by an underscore. So in our case, we’re calling this our “core” frame,
and thus prefixing it by hello_world to make sure that no other module steals
this frame name.
Inside our frame, we have a <Script> tag, which really is the events handling
section of our frame. In here you can have various events, but <OnLoad> and <OnEvent>
are going to be the ones that you probably use the most often.
As its name indicates, any code inside the <OnLoad> tag is executed when your
AddOn loads (this occurs after you choose a character to log in, but before the
loading screen ends – in other words, your AddOn does *not* load for the login
screen, etc).
In our OnLoad event, we register “this” for an event called “VARIABLES_LOADED”.
“this” is the frame that we currently are in, so “this” really refers to
“hello_world_core” (frames are variables/objects of sorts). The colon ( : )
after signifies that we are running a function that is inherit to that frame, in
this case, the function RegisterEvent, which tells the game to notify your frame
whenever the “VARIABLES_LOADED” event happens.
This leads us to the <OnEvent> tag. A variable by the name of “event” is
*always* defined here, and contains the name of the event that is being
triggered. So we check to make sure that the event fired is the one we want,
namely VARIABLES_LOADED, and then perform some operations when it is fired.
Now, this brings me to another important point, so pay attention. Recently, the
guys over at Blizzard gave us an awesome new feature: saved variables. However,
in order to implement this, things got a tad more confusing. You can use the
function RegisterForSave(“variable_name”) to specify that a variable is to be
saved across game sessions. However, if you set a value to that variable before
the VARIABLES_LOADED event is fired, it could be overwritten by the saved value.
In other words, set your default settings before VARIABLES_LOADED is fired, and
then make any changes/initializations *after* it is fired.
Finally, in our case, when VARIABLES_LOADED is fired, we call the function
hello_world_initialize(). Ah crap, but we haven’t written it yet :(
c. Fleshing it All Out
So, this brings us to the actual coding that goes on around here. Create a file
called hello_world.lua. Here’s what we’re going to stick in it. Nothing fancy:
function hello_world_initialize()
-- add our very first chat command!
SlashCmdList["HELLOW"] = hello_world_command;
SLASH_HELLOW1 = "/hellow";
SLASH_HELLOW2 = "/hw";
end
function hello_world_command(msg)
-- this function handles our chat command
message(msg);
end
I’m not going to comment on the actual syntax used, as the actual LUA
documentation describes it far better than I could ever hope to. You can read
about that here:
http://www.lua.org/manual/5.0/
Bear in mind that the input/output library, operating system library (and
possibly the coroutine and reflexive debug system - I haven't gotten around to
testing them yet) are *not* included in the blizzard UI. So basically you've got
access to the math, string, and table functions.
For a list of Blizzard-defined functions and events, you can check them out
here, courtesy of the excellent effort put forth by the Cosmos guys (and many
untold hours of research):
http://www.cosmosui.org/texts/BlizzardCommands.xml
Anyway, back to our code. In our initialization function, we define a chat
command. This may seem strange, and indeed, it is – as we are modifying the
“table” (these are basically associative arrays) SlashCmdList. The explanation
of *how* this works exactly is out of the scope of this article, just for now,
take my word – this adds a chat command where you can type either /hellow
<message>, or /hw <message> - which will then call the function
“hello_world_command” when a user types in said command.
Which is why we defined the function hello_world_command to handle our chat
command (one variable is passed to all chat command functions, which is
everything typed after the initial command, the <message>).
So in a nutshell, this simple AddOn adds two new chat commands. To test them,
start up the game (if you already have it running, simply type “/console
reloadui” into your chat to reload the interface). Once you log in as one of
your characters, try typing:
/hellow Why hello there!
You should get a popup window with “Why Hello there!” Joy!
4. Finishing up…. For now…
So that’s it for our rudimentary example. I’ll whip up some more advanced
examples (perhaps with some real interface components, like….
buttons! and… and… animation!) when I am
slightly less exhausted, and slightly more sane.
But if you made it this far, I applaud you! That’s a lot of reading.
For the overzealous lot, here’s a bit of homework. Read through the LUA manual
(found at
http://www.lua.org/manual/5.0/), and skim over the Blizzard-defined
functions (found at
http://www.cosmosui.org/texts/BlizzardCommands.xml). Finally, in your copy
of the Interface folder (where you extracted FrameXML) – check out the file:
Interface/FrameXML/BasicControls.xml
This handles the message() function you saw earlier, as well as a few other
things. (you may want to check out Fonts.xml as well, and see if you can find a
better font for the ScriptErrors frame – perhaps a smaller one, and maybe a
different color, that’s easier on the eyes)
The latest copy of the WoW API Docs can be found at:
http://www.wowwiki.com/Interface_Customization
|
|