base

Global functions of Lua 5.1 / LuaJIT 2.1 and what the client changes in them.

The global functions of Lua 5.1 / LuaJIT 2.1, documented without prefix, with the changes the sandbox makes to them.

At a glance

Group Functions
Errors assert, error, pcall, xpcall
Loading load, loadstring, require, module
Types and conversion type, tonumber, tostring
Tables next, pairs, ipairs, select, unpack, rawequal, rawget, rawset
Metatables and environments getmetatable, setmetatable, getfenv, setfenv, newproxy
Memory collectgarbage, gcinfo
Output print
Constants _G, _VERSION

What the client changes:

Item State
dofile, loadfile Removed (nil). Run a file with load(xiao.fs.read(path)).
load, loadstring Replaced: text source only, bytecode is refused. load ignores a mode or env argument.
require Searches C:\xiaohook\lua only, no native modules.
print Replaced: writes one line to the client console.
ffi, io Not available.
jit The LuaJIT jit library is present (jit.on, jit.off, jit.flush, jit.status, jit.opt, jit.version, jit.os, jit.arch).

Errors that reach the client are shown in red in the console with the file name, the line and a traceback. A script that runs too long is stopped, see Time limits.


Errors

assert(v, message): any

assert(v: any, message?: any): any

Raises an error if v is nil or false, otherwise returns all its arguments.

Name Type Description
v any value to test
message any error value when the test fails, default "assertion failed!"

Returns: v and every other argument. Errors: message (raised as is, no position is added), or assertion failed!.

local n = assert(tonumber("42"), "not a number")

error(message, level)

error(message: any, level?: number = 1)

Raises message as an error and never returns.

Name Type Description
message any the error value
level number for a string message, where the position comes from: 1 the function calling error, 2 its caller, 0 no position

Returns: never.

local function check(n)
    if type(n) ~= "number" then error("number expected", 2) end
    return n
end

pcall(f, ...): boolean, any

pcall(f: function, ...: any): boolean, ...any

Calls f(...) in protected mode.

Name Type Description
f function function to call
... any arguments for f

Returns: true and every result of f, or false and the error value. Errors: bad argument #1 to 'pcall' (value expected) when called without argument.

local ok, err = pcall(xiao.fs.read, "missing.txt")
if not ok then print("read failed:", err) end

xpcall(f, handler, ...): boolean, any

xpcall(f: function, handler: function(err: any): any, ...: any): boolean, ...any

Like pcall, but calls handler with the error value before the stack unwinds, so it can build a traceback. LuaJIT passes the extra arguments to f.

Name Type Description
f function function to call
handler function receives the error value, its result is returned
... any arguments for f

Returns: true and every result of f, or false and the result of handler.

local ok, trace = xpcall(function(a, b) return a + b end, debug.traceback, 1, nil)

Loading code

load(chunk, chunkname): function | nil, string

load(chunk: string | function, chunkname?: string = "=(load)"): function | nil, string

Compiles a chunk of Lua source and returns it as a function. The function runs in the global environment, use setfenv to change it.

Name Type Description
chunk string or function the source, or a reader called until it returns nil or "", each call returning the next piece
chunkname string name used in error messages and tracebacks

Returns: the compiled function, or nil and the error message (syntax error, or attempt to load chunk with wrong mode for bytecode). Errors: reader function must return a string when the reader returns something else.

local f, err = load("return 1 + 2", "=sum")
print(f and f() or err)

loadstring(text, chunkname): function | nil, string

loadstring(text: string, chunkname?: string = text): function | nil, string

Same as load for a string. The chunk name defaults to the text itself, so errors read [string "..."]:1: ....

Name Type Description
text string Lua source
chunkname string name used in error messages

Returns: the compiled function, or nil and the error message. Bytecode gives attempt to load chunk with wrong mode.

local f = loadstring("return ...")
print(f("a", "b"))

require(name): any

require(name: string): any

Loads a module once and returns its value. Later calls return the cached value from package.loaded[name]. See Modules with require.

Name Type Description
name string module name, dots are folder separators: lib.util is lib/util.lua

Search order:

  1. package.preload[name]. LuaJIT preloads table.new, table.clear, string.buffer and jit.util; the client removes jit.profile, whose callback would run outside the time limits.
  2. C:\xiaohook\lua\<name>.lua, then C:\xiaohook\lua\<name>/init.lua. Paths follow the sandbox rules and cannot leave C:\xiaohook\lua.

The module chunk receives name as .... If it returns a non-nil value it is stored in package.loaded[name], otherwise true is stored. Error positions read lib/util.lua:3:.

Returns: the module value. Errors:

  • not found: module 'lib.util' not found: followed by no field package.preload['lib.util'], no file 'lib/util.lua' and no file 'lib/util/init.lua'
  • syntax error: error loading module 'lib.util': ...
  • refused path: the sandbox message, for example path escapes the xiaohook folder: ../x.lua
  • a module that failed once: loop or previous error loading module 'lib.util' until package.loaded[name] is set to nil or the VM is cleared
local util = require("lib.util")

Types and conversion

type(v): string

type(v: any): string
Name Type Description
v any value to inspect

Returns: "nil", "boolean", "number", "string", "table", "function", "thread" or "userdata". Client objects (colors, vectors, images, packets, commands) are "userdata".

tonumber(v, base): number | nil

tonumber(v: any, base?: number = 10): number | nil
Name Type Description
v any value to convert
base number 2 to 36. Without it, decimal, 0x hexadecimal and exponent forms are accepted

Returns: the number, or nil when v cannot be converted. Errors: bad argument #2 to 'tonumber' (base out of range).

print(tonumber("ff", 16), tonumber("0x10"), tonumber("abc"))

tostring(v): string

tostring(v: any): string
Name Type Description
v any value to convert

Returns: the string. Uses the __tostring metamethod when present. Tables, functions, threads and userdata give type: 0x..., built-in functions function: builtin#29.


Tables and iteration

next(t, key): any, any

next(t: table, key?: any): any, any
Name Type Description
t table table to traverse
key any previous key, nil for the first pair

Returns: the next key and its value, or nil at the end. The order is not specified. Assigning a new key during a traversal is undefined; clearing an existing one is allowed.

pairs(t): function, table, nil

pairs(t: table): function, table, nil
Name Type Description
t table table to traverse

Returns: next, t and nil, for a generic for over every pair. __pairs is not honoured on tables.

for k, v in pairs({ x = 1, y = 2 }) do
    print(k, v)
end

ipairs(t): function, table, number

ipairs(t: table): function, table, number
Name Type Description
t table array to traverse

Returns: an iterator, t and 0. The loop visits 1, t[1], 2, t[2]... and stops at the first nil.

for i, v in ipairs({ "a", "b", "c" }) do
    print(i, v)
end

select(index, ...): any

select(index: number | string, ...: any): ...any
Name Type Description
index number or "#" position of the first value to return, negative counts from the end; "#" counts the values
... any the values

Returns: the values from index on, or their count for "#". Errors: bad argument #1 to 'select' (index out of range).

print(select("#", 1, nil, 3), select(2, "a", "b", "c"))

unpack(t, i, j): any

unpack(t: table, i?: number = 1, j?: number = #t): ...any
Name Type Description
t table array
i, j number first and last index

Returns: t[i] to t[j] as multiple values. table.unpack does not exist in Lua 5.1. Errors: too many results to unpack.

print(unpack({ 10, 20, 30 }, 2))

rawequal(a, b): boolean

rawequal(a: any, b: any): boolean
Name Type Description
a, b any values to compare

Returns: true if a and b are primitively equal, ignoring __eq.

rawget(t, key): any

rawget(t: table, key: any): any
Name Type Description
t table table to read
key any key

Returns: t[key] without calling __index.

rawset(t, key, value): table

rawset(t: table, key: any, value: any): table
Name Type Description
t table table to write
key any key, not nil or NaN
value any value

Returns: t. __newindex is not called. Errors: table index is nil, table index is NaN.


Metatables and environments

getmetatable(obj): table | any

getmetatable(obj: any): table | any
Name Type Description
obj any value to inspect

Returns: the metatable, its __metatable field when set, or nil. Strings share one metatable whose __index is string.

setmetatable(t, mt): table

setmetatable(t: table, mt: table | nil): table
Name Type Description
t table table to change
mt table or nil new metatable, nil removes it

Returns: t. Errors: cannot change a protected metatable when the current one has __metatable.

local counter = setmetatable({}, { __index = function() return 0 end })
print(counter.hits)

getfenv(f): table

getfenv(f?: function | number = 1): table
Name Type Description
f function or number a function, or a stack level: 1 the caller, 2 its caller, 0 the global environment

Returns: the environment table.

setfenv(f, env): function

setfenv(f: function | number, env: table): function
Name Type Description
f function or number a Lua function or a stack level, 0 for the running thread
env table new environment

Returns: the function (nothing for level 0). Errors: 'setfenv' cannot change environment of given object for a C function.

local chunk = load("x = 1")
local sandbox = {}
setfenv(chunk, sandbox)
chunk()
print(sandbox.x, x)

newproxy(arg): userdata

newproxy(arg?: boolean | userdata): userdata
Name Type Description
arg boolean or userdata true gives the userdata a fresh metatable, another proxy shares its metatable

Returns: a new empty userdata. Errors: bad argument #1 to 'newproxy' (boolean or proxy expected).


Memory

collectgarbage(opt, arg): number | boolean

collectgarbage(opt?: string = "collect", arg?: number = 0): number | boolean
Name Type Description
opt string one of the options below
arg number parameter of step, setpause and setstepmul
opt Effect and result
"collect" full collection cycle, returns 0
"stop", "restart" stops or restarts the collector, returns 0
"count" memory used by Lua in kilobytes, fractional
"step" one collection step, true if it finished a cycle
"setpause", "setstepmul" sets the parameter to arg (percent), returns the previous value
"isrunning" true while the collector is running

Errors: bad argument #1 to 'collectgarbage' (invalid option 'x').

print(("lua memory: %.0f KB"):format(collectgarbage("count")))

gcinfo(): number

gcinfo(): number

Returns: memory used by Lua in whole kilobytes. Old form of collectgarbage("count").


Output

print(...)

Writes one line to the client console, not to stdout. It works in every context, packet and cmd hooks included.

Name Type Description
... any values converted with the global tostring and separated by a tab

Returns: nothing. A line longer than 4096 bytes is cut, and the console keeps the last 512 lines. Errors: tostring must return a string to print.


Constants

_G: table

The global environment table. _G._G == _G.

_VERSION: string

The string "Lua 5.1". Use jit.version for the LuaJIT version.


Complete example

Load a module, report its error with a traceback, and allow a retry after fixing the file.

local function try_require(name)
    local ok, value = xpcall(require, debug.traceback, name)
    if ok then return value end
    package.loaded[name] = nil
    print("cannot load " .. name .. ": " .. tostring(value))
    return nil
end

local util = try_require("lib.util")
if util ~= nil then
    print("lib.util loaded:", type(util))
end
print(_VERSION, jit.version, ("%.0f KB"):format(collectgarbage("count")))