(Switch to: Lua · Python · Level Generation · Tensor · Text Levels · Build · Known Issues)
DeepMind Lab provides a number of ways for Lua callback functions to hook into various game events.
On construction of the environment, the levelName setting specifies a game
script file name. Game script files live in the game_scripts directory
and end in .lua. They consist of Lua code that should return an object
implementing some of the API functions below.
The environment will periodically attempt to call these functions in order to determine its behaviour. However, in most cases there is some appropriate default behaviour that takes place if the corresponding API function is not defined.
In order to successfully load a map, at least nextMap should be provided by
the game script.
The calling code that calls into these API functions can be found in deepmind/engine/context.cc.
Called at beginning of the level to populate the level with in-game
bots. Returns an array of tables, each of which has a name and skill
entry. Each skill should be a number between 1 and 5.
The environment calls this function to decide whether the item with ID
entity_id is allowed to be picked up. Return false to disallow
pickup. Defaults to true if the callback function isn't implemented.
The environment calls this function at the very beginning to determine the
initial engine console commands. The old_commandline parameter is the default
value, which you should return as-is if you do not want to customize the command
sequence.
Example:
function api:commandLine(old_command_line)
return "+set r_fullscreen \"1\""
endLists of available commands in Quake III Arena can be found online.
Returns a table with keys name, class_name, model_name, quantity,
type, and an optional tag.
(For information on DeepMind Lab's tensor library, see Tensor.)
When called it must return a tensor of a matching shape and type as specified in
customObservationSpec.
Example:
local order = 'Find Apples!'
local observationTable = {
LOOK_PITCH = tensor.Tensor{0},
ORDER = tensor.ByteTensor(order:byte(1, -1)),
LOCATION = tensor.Tensor{0, 0, 0},
}
function api:customObservation(name)
return observationTable[name]
endCalled after init, it returns an additional array of extra
observation types supplied by the script.
Each entry must contain a name, type and shape.
nameName of the observation reported by the environment.typeType of tensor returned by the environment. May only be "bytes" or "doubles".shapeAn array of integers denoting the shape of the tensor. If the size of any dimension can change between calls, it must be set to zero here.
-- See customObservation how to implement these.
function api:customObservationSpec()
return {
{name = 'LOCATION', type = 'doubles', shape = {3}},
{name = 'ORDER', type = 'bytes', shape = {0}},
{name = 'LOOK_PITCH', type = 'doubles', shape = {1}},
}
endWhen this function is specified the environment may call observation with any
name specified in the spec.
Called at game startup with the table settings representing a key-value store for all settings passed at the start of the environment which weren't consumed by the engine itself. See python_api.md for settings consumed by the engine.
Example:
function api:init(settings)
print("Script Settings")
for k, v in pairs(settings) do
print(k .. " = " .. v)
end
io.flush()
endCalled at the end of every frame with the elapsed time as an argument to determine if the episode has finished and the game evaluation should continue with the next episode.
The default implementation returns false until 5 minutes have passed.
Called whenever a map needs to be loaded. Must return the name of a map discoverable by the engine.
For more information on maps, see Maps below.
Event handler when the item with id spawn_id is picked up. Returns the respawn time.
The environment calls this function at the start of each episode, with:
- A number episode, starting from 0.
- A number seed, the random seed of the game engine. Supplying the same seed is intended to result in reproducible behaviour.
Example:
function api:start(episode, seed)
print("Entering episode no. " .. episode .. " with seed " .. seed)
io.flush()
endCalled once per spawn_vars entry when a new map is loaded. The spawn_vars
argument is a Lua table with the internal Quake III Arena spawnVars key-value
setting. Quake III Arena maps define a list of entities
(light sources, player start points, items, ...). Implementing this function
allows overriding the settings for each map entity.
The default implementation returns spawn_vars unchanged.
Called once at the start of each episode, can be used to supply an int interpreted as a bitmap of buttons that will not be allowed to be used in the environment. The bitmap uses the convention of deepmind/engine/code/qcommon/q_shared.h.
Called everytime a bot with id bot_id collides with a player with id bot_id. Can be used to bind specific logic to these kind of collisions.
Called at every update of any bot, can be used to pass down a speed and a velocity vector
that will be used as input for that bot. Returning a speed of 0 leads to the bot being
updated following the standard AI. The returned table must have a speed property interpred
as a float and optionally three properties velocityX, velocityY and velocityZ used
as input velocity vector. View rotations are currently not supported.
A number of helper functions can be found in game_scripts/common. They
can be used in game scripts via Lua's require statement, for example:
local make_map = require 'common.make_map'
function api:nextMap()
return make_map.makeMap("G I A P", "my_map")
endReturns a Lua object offering a makeMap
and a commandLine function.
Returns a Lua object offering a type and defaults table for
defining pickup objects.
Game scripts can interact with DeepMind Lab using the dmlab.system.game
module, which can be loaded using local game = require 'dmlab.system.game'.
The module provides the following functions.
Adds a score to the total score of the player with player_id.
Finishes the current map.
DeepMind Lab provides a number of Lua files with auxiliary helper functions in
the game_scripts/helpers directory. Among them are factories, which are of
the form
local factory = {}
function factory.createLevelApi(kwargs)
local api = {}
-- ...
return api
end
return factoryFor examples, see any game_scripts/helpers/*_factory.lua file. Factory
functions can be used as a higher-level API for creating game scripts. As an
example, the lt_chasm.lua game script is implemented via
local factory = require 'helpers.lt_factory'
return factory.createLevelApi{mapName = "lt_chasm"}DeepMind Lab maps are identified by strings representing a file name. This
file must contain a Quake III Arena map, see
Level Generation for a description of
those. DeepMind Lab also defines a text level
format which provides a simple text format for creating levels. The Lua module
game_scripts/common/make_map.lua provides a convenient interface for making
maps from ASCII text level strings on the fly, namely
Generates a map called map_name from map_text. The map name acts as a file name and should be unique. For a description of the text level format that map_text uses, see Text Levels.
An example usage of makeMap is
local make_map = require 'common.make_map'
...
function api:nextMap()
map_text = "G I A P"
api._count = api._count + 1
return make_map.makeMap(map_text, "luaMap" .. api._count)
endwhere api._count would have been set up in start. The tests/demo_map.lua
game script file provides a self-contained example.
Called to enable the script to render text on the screen at arbitrary locations.
args is a table containing:
width- Virtual screen width. (Always 640.)height- Virtual screen height. (Always 480.)line_height- Distance to move vertically between lines. (Always 20.)max_string_length- Maximum length of string per message (Always 79.)
The user must return an array of messages. Each message shall contain:
message- String for the screen to render.x- X location to render the string. (0 is left edge, 640 is right.)y- Y location to render the string. (0 is top edge, 480 is bottom.)alignment- 0 left aligned, 1 right aligned, 2 center aligned.
Helpers for rendering some message types are in common.screen_message:
local screen_message = require 'common.screen_message'
function api:screenMessages(args)
local message_order = {
message = 'Find an apple!',
x = args.width / 2,
y = (args.height - args.line_height) / 2,
alignment = screen_message.ALIGN_CENTER,
}
return { message_order }
end