Libraries and functions

Factorio provides the Lua environment several functions and libraries that cannot be found in standard Lua 5.2.1. Furthermore, it modifies some functions to be deterministic, notably pairs() and math.random().

1. Libraries

serpent

Factorio provides the serpent library as a global variable serpent for all mods to use. This is done because Factorio uses serpent for the serialization of the global table. It also allows for easy debugging of tables, because serpent makes it trivial to print them, for example by using serpent.block(). However, serpent cannot pretty-print LuaObjects such as LuaEntity. The serpent library was modified to improve determinism, e.g. comments are turned off by default to avoid returning table addresses.

2. New functions

log()

This function allows to log LocalisedStrings to the Factorio log file. This, in combination with serpent, makes debugging in the data stage easier, because it allows to simply inspect entire prototype tables.

table_size()

Factorio provides the function table_size() as a simple way to find the size of tables with non-continuous keys, because the standard # does not work correctly for these. The function is a C++-side implementation of the following Lua code, thus it is faster than using this code in Lua.

  local function size(t)
    local count = 0
    for k,v in pairs(t) do
      count = count + 1
    end
    return count
  end

3. Modified functions

Some modules that are part of standard Lua are not accessible in Factorio's Lua environment, mostly to ensure determinism. These inaccessible modules are: loadfile(), dofile(), coroutine, io and os. Factorio provides its own version of package.

pairs()

In standard Lua, the order of iteration when using pairs() is arbitrary. Because Factorio has to be deterministic, this was changed in Factorio's version of Lua. Factorio's iteration order when using next(), which pairs() uses for iteration, depends on the insertion order: Keys inserted first are iterated first. However, Factorio also guarantees that the first 1024 numbered keys are iterated from 1-1024, regardless of insertion order. This means that in usual usage, pairs() does not have any drawbacks compared to ipairs().

print()

print() outputs to the stdout. For Factorio, this means that it does not end up in the log file, so it can only be read when starting Factorio from the command line. Because of this, it is often easier to use log() or LuaGameScript::print for debugging.

require()

Due to the changes to package, the functionality of require() changes. When using absolute paths, the path starts at the mod root, additionally .. is disabled as a path variable. This means that it is not possible to load arbitrary files from outside the mod directory. However, Factorio provides two ways to load files from other mods:

require() can not be used in the console, in event listeners or during a remote.call(). The function expects any file to end with the .lua extension.

math.random()

math.random() is implemented within Factorio so that it is deterministic, in both the data stage and during runtime scripting. In the data stage, it is seeded with a constant number. During runtime scripting, it uses the map's global random generator which is seeded with the map seed. The map's global random generator is shared between all mods and the core game, so they can affect the random number that is generated. If that behaviour is not desired, LuaRandomGenerator can be used to create a random generator that is completely separated from the core game and other mods. In the runtime stage, math.random() cannot be used outside of events or during loading.

math.randomseed()

Using math.randomseed() in Factorio has no effect on the random generator, the function does nothing. If custom seeding or re-seeding is desired, LuaRandomGenerator can be used instead of math.random().