base
The global functions of Lua 5.1 / LuaJIT 2.1, documented without prefix, with the changes the sandbox makes to them.
At a glance
What the client changes:
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.
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.
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.
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.
Time limits
A timeout is not a normal error. pcall can return false once, but the client raises the error again on every following instruction until the call into the VM ends, so the script cannot continue. See Time limits.
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.
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.
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: ....
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.
Search order:
package.preload[name]. LuaJIT preloadstable.new,table.clear,string.bufferandjit.util; the client removesjit.profile, whose callback would run outside the time limits.C:\xiaohook\lua\<name>.lua, thenC:\xiaohook\lua\<name>/init.lua. Paths follow the sandbox rules and cannot leaveC:\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 byno field package.preload['lib.util'],no file 'lib/util.lua'andno 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'untilpackage.loaded[name]is set tonilor the VM is cleared
local util = require("lib.util")
To run a file every time without caching it, use load(xiao.fs.read("lua/script.lua"))(), see xiao.fs. module(name, package.seeall) fails because package.seeall is removed: return a table from the module instead.
Types and conversion
type(v): string
type(v: any): string
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
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
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
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
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
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
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
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
Returns: true if a and b are primitively equal, ignoring __eq.
rawget(t, key): any
rawget(t: table, key: any): any
Returns: t[key] without calling __index.
rawset(t, key, value): table
rawset(t: table, key: any, value: any): table
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
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
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
Returns: the environment table.
setfenv(f, env): function
setfenv(f: function | number, env: table): function
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
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
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(...)
print(...: any)
Writes one line to the client console, not to stdout. It works in every context, packet and cmd hooks included.
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.
print("pos", 1.5, true, nil)
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")))