Skip to content

API Reference

Getting started

Check out the getting started page to learn how to setup a script development environment.

Most interactions with the game state take place through the global access variable wow. For more information, check out the globals documentation.

Lua script requirements

Each script AI should create an entrypoint script that defines a function main. The main function will be called every 50ms or so depending on server performance (referred to as a 'tick'). The function should read in game state data and perform actions as appropriate. The main function should return when processing is complete.

Even though most actions block (i.e. directly execute), it is possible to perform multiple actions per bot depending on the action (i.e. actions that don't affect GCD, like taking a pot or printing information). The following code snippet demonstrates having each bot activate both their trinkets in the same tick:

local has_used_trinkets = false

local function main()
    if not has_used_trinkets then
        for bot in each(wow.bots) do
            bot.trinket_1:use()
            bot.trinket_2:use()
        end
        has_used_trinkets = true
    end
end

It should be noted that the results of actions are not guaranteed to be immediately present in the game state data after an action is performed.

Libraries

The lua scripting API supports libraries provides a set of 1st-party libraries that ship with lua. They are:

Library Description
base Provides various basic functions like ipairs
package Provides support for packages via require (and custom modules)
coroutine Provides support for coroutines, roughly 'parallel execution'
string Provides various features for working with strings
math Provides various functions for performing math via math
table Provides various tools to maniplate tables like table.insert

Json

A json library comes with the server and can be brought in by using json = require("json"). The json library used is here.

These are the functions available on the json module:

json.encode({ 1, 2, 3, { x = 10 } }) -- Returns '[1,2,3,{"x":10}]'
json.decode('[1,2,3,{"x":10}]') -- Returns { 1, 2, 3, { x = 10 } }
Function Description Parameters Return Type Tested?
encode Returns a string representing value encoded in JSON object data string Yes
decode Returns a value representing the decoded JSON string string value object Yes

Custom Modules

playerbot-lua supports custom modules that work in the same way they would with normal lua files using their relative path to the source root. Modules are importable through the same usage of require. Given the following files:

modules/test.lua

test = {}

function test.print_bot_name(bot)
    print(bot.name)
end

return test

main.lua

test = require("modules/test")

function main()
    for _, bot in ipairs(wow.bots) do
        test.print_bot_name(bot)
    end
end

The module import would work as expected and a list of bot names would be printed.

Pointers

While memory objects are retained between ticks when created and managed in lua, all pointers to objects that are not managed by lua (e.g. a Player managed by the server) should not be trusted to persist at the same memory location between ticks. As such, it is recommended to only store value type objects provided by the API between ticks.

For example, the following code may be written to store bot CC assignments:

local cc_assignments = {}

local function main()
    for bot in each(wow.bots) do
        -- notice the usage of a pointer as the key
        if bot.class == wow.enums.classes.mage and not cc_assignments[bot] then
            cc_assignments[bot] = wow.raid_icons.moon
        end
    end
end

This strategy for storing CC assignments may seem appealing at first as it provides an easy way to uniquely identify and track assignments. For example, when individual mage behavior is being decided, the following code could be written:

-- in a mage decision function
local cc_target = cc_assignments[bot]
if cc_target then
    bot:cast(cc_target, POLYMORPH_SPELL_ID)
end

The issue arises in the next tick as the previous assignment would still be present with the previous pointer identifying the bot. When cc_assignments is indexed to see if the bot has an assignment, the bot pointer available will notmatch the original pointer by value. As such the mage Playerbot will not correctly cast the correct spell.

A better strategy might be to use the name of the bot as the key. Since it is a string and therefore a value type, it will represent the bot well between ticks. For example:

-- set
cc_assignments[bot.name] = wow.raid_icons.moon

-- get
local cc_target = cc_assignments[bot.name]

The bot object's id member would suffice as well.

Note- pointers provided from the API can be trusted to be consistent during the same tick. In the above example, if cc_assignments was repopulated at the beginning of each tick with the latest pointer, later iterations over the wow.bots array would provide the same pointers and equality would work as expected.

Garbage Collection

The lua instance automatically garbage collects using internal best practices to retain high performance. Since the server understands that lua will be repeatedly executed, in each tick, after lua code execution, the server manually invokes garbage collection.

Issues

Bug reports, suggestions, or any other questions should be created as issues here.