- Lua 74.9%
- C++ 11.5%
- C 8.3%
- C# 5.3%
| inc | ||
| src | ||
| .gitignore | ||
| BlockLua.dll | ||
| lua5.1.dll | ||
| readme.md | ||
BlockLua
Lua scripting for Blockland made by Redo
How to Install
- Install RedBlocklandLoader
- Copy
lua5.1.dllinto your Blockland install folder, next toBlockland.exe - Copy
BlockLua.dllinto themodulesfolder within the Blockland folder (you may have to create it)
Quick Reference
From TorqueScript
'print('hello world') - Execute Lua in the console by prepending a ' (single quote)
luaeval("code"); - Execute Lua code
luacall("funcName", %args...); - Call a Lua function (supports indexing tables and object methods)
luaexec("fileName"); - Execute a Lua file. Path rules are the same as when executing .cs files. Relative paths are allowed.
luaget("varName"); - Read a Lua global variable (supports indexing tables)
luaset("varName", %value); - Write a Lua global variable (supports indexing tables)
From Lua
bl.eval('code') - Eval TorqueScript code
bl.funcName(args) - Call a TorqueScript function
bl.varName - Read a TorqueScript global variable
bl['varName'] - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array)
bl.set('varName', value) - Write a TorqueScript global variable
bl['namespaceName::funcName'](args) - Call a namespaced TorqueScript function
Accessing Torque Objects from Lua
bl.objectName - Access a Torque object by name
bl[objectID] - Access a Torque object by ID (or name)
object.fieldOrKey - Read a field or Lua key from a Torque object
object:set('field', value) - Write a field on a Torque object
object.key = value - Associate Lua data with a Torque object
object:method(args) - Call a Torque object method
object[index] - Access a member of a Torque set or group
for child in object:members() do - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
bl.isObject(object, objectID, or 'objectName') - Check if an object exists
object:exists() - Check if an object exists
Timing/Schedules
sched = bl.schedule(timeMs, function, args...) - Schedule a Lua function to be called later, similar to schedule in Torque
bl.cancel(sched) - Cancel a previously scheduled timer
Raycasts and Searches
hitObject, hitPos, hitNormal = bl.raycast(vector{startPosX,y,z}, vector{endPosX,y,z}, 'objtype'/{'objtypes',...}, {ignoreObjects...}?) - Cast a ray in the world over objects of the specified type(s) (possibly excluding some objects), and return the object hit, the position of the hit, and the normal vector to the surface hit. Returns nil if nothing is hit. See the Types section for a list of valid object types.
for object in bl.boxSearch({vector{centerX,y,z}, vector{sizeX,y,z}}, 'objtype'/{'objtypes',...}) do - Find all objects in the world of the specified type(s) whose bounding box overlaps with the specified box. See the Types section for a list of valid object types.
for object in bl.radiusSearch(vector{centerX,y,z}, radius, 'objtype'/{'objtypes',...}) do - Find all objects of the specified type(s) whose bounding box overlaps with the specified sphere. See the Types section for a list of valid object types.
List of Object Classes (for raycasts and searches)
'all' - Any object
'player' - Players or bots
'item' - Items
'vehicle' - Vehicles
'projectile' - Projectiles
'brick' - Bricks (only those with raycasting enabled)
'brickalways' - All bricks including those with raycasting disabled
Other types: 'static', 'environment', 'terrain', 'water', 'trigger', 'marker', 'gamebase', 'shapebase', 'camera', 'staticshape', 'vehicleblocker', 'explosion', 'corpse', 'debris', 'physicalzone', 'staticts', 'staticrendered', 'damagableitem'
Server-Client Communication
bl.addServerCmd('commandName', function(client, args...) ... end) - Register a /command on the server
bl.addClientCmd('commandName', function(args...) ... end) - Register a client command on the client
bl.commandToServer('commandName', args...) - As a client, execute a server command
bl.commandToClient(client, 'commandName', args...) - As the server, execute a client command on a specific client
bl.commandToAll('commandName', args...) - As the server, execute a client command on all clients
Packages/Hooks
bl.hook('packageName', 'functionName', 'before'/'after', function(args) ... end) - Hook a Torque function with a Lua function.
args is an array containing the arguments provided to the function. If the hook is before, these can be modified before being passed to the parent function.
If args._return is set to anything other than nil by a before hook, the parent function will not be called, and the function will simply return that value. Also in this case, any after hook will not be executed.
In an after hook, args._return is set to the value returned by the parent function, and can be modified.
bl.unhook('packageName', 'functionName', 'before'/'after') - Remove a previously defined hook
bl.unhook('packageName', 'functionName') - Remove any previously defined hooks on the function within the package
bl.unhook('packageName') - Remove any previously defined hooks within the package
Modules and Dependencies
dofile('Add-Ons/Path/file.lua') - Execute a Lua file. Relative paths (./file.lua) are allowed. .. is not allowed.
require('modulePath.moduleName') - Load a Lua file or external library.
require replaces . with / in the path, and then searches for files in the following order:
./modulePath/moduleName.lua./modulePath/moduleName/init.luamodulePath/moduleName.lua(Relative to game directory)modulePath/moduleName/init.lua(Relative to game directory)modules/lualib/modulePath/moduleName.luamodules/lualib/modulePath/moduleName/init.luamodules/lualib/modulePath/moduleName.dll- C libraries for Lua can be loaded
Like in standard Lua, modules loaded using require are only executed the first time require is called with that path (from anywhere). Subsequent calls simply return the result from the initial execution. For hot reloading, use dofile instead.
File I/O
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
Relative paths (./) are allowed. .. is not allowed.
file = io.open('./file.txt', 'r'/'w'/'a'/'rb'/'wb'/'ab') - Open a file
file:read(numberOfChars/'*a') - Read an opened file (must be opened in 'r' (read) or 'rb' (read binary) mode)
file:write(string) - Write an opened file (must be opened in 'w' (write), 'a' (append), 'wb' or 'ab' mode)
file:close() - Close an opened file
Reading files from ZIPs is supported with caveats: Null characters are not allowed, and \r\n becomes \n. Generally, text formats work, and binary formats don't.
When reading and writing outside ZIPs, binary files are fully supported.
for filename in bl.findFiles('dir/pattern/*.ext') do - Search for files (recursing within dirs) matching the pattern, where * is a wildcard matching 0 or more characters including /.
Object Creation
bl.new('className') - Create a new Torque object
bl.new('className', {fieldName = value, ...}) - Create a new Torque object with the given fields
bl.new('className objectName', fields?) - Create a new named Torque object
bl.new('className objectName:parentName', fields?) - Create a new named Torque object with inheritance
bl.datablock('datablockClassName datablockName', fields?) - Create a new datablock
bl.datablock('datablockClassName datablockName:parentDatablockName', fields?) - Create a new datablock with inheritance
Classes and Types
bl.type('varName', 'type') - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'object', 'boolean', 'string' (prevents automatic conversion), and nil (default, applies automatic conversion).
bl.type('funcName', 'type') - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all default functions.
bl.type('funcName:argIndex', 'type') - Register the type of a Torque function argument, for conversion when that function is hooked from Lua using bl.hook
bl.type('classOrNamespace::funcName', 'type') - Register the return type of a Torque namespaed function / object method.
bl.type('classOrNamespace::funcName:argIndex', 'type') - Register the arg type of a Torque namespaced function / object method.
bl.type('@luaVarName', 'type') - Register the type of a Lua variable for conversion when setting that variable from TorqueScript
bl.type('@luaTable.luaVar', 'type') - Register the type of a Lua variable within any number of nested tables
bl.type('@luaFuncName:argIndex', 'type') - Register the type of a Lua function argument, for conversion when calling that function from TorqueScript
bl.type('@luaTable.luaFuncName:argIndex', 'type') - Register the type of a Lua function argument within any number of nested tables
bl.type('@luaTable:luaFuncName:argIndex', 'type') - Register the type of a Lua method argument within any number of nested tables
bl.class('className') - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
bl.class('className', 'parentClassName') - Register an existing Torque class with inheritance
bl.boolean(arg) - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
bl.object(arg) - Manually convert a Torque object reference (object ID or name) into a Lua object.
Vector
vec = vector{x,y,z} - Create a vector. Can have any number of elements
vec1 + vec2 - Add
vec1 - vec2 - Subtract
vec * number - Scale (x*n, y*n, z*n)
vec / number - Scale (x/n, y/n, z/n)
vec ^ number - Exponentiate (x^n, y^n, z^n)
vec1 * vec2 - Multiply elements piecewise (x1*x2, y1*y2, z1*z2)
vec1 / vec2 - Divide elements piecewise (x1/x2, y1/y2, z1/z2)
vec1 ^ vec2 - Exponentiate elements piecewise (x1^x2, y1^y2, z1^z2)
-vec - Negate/invert
vec1 == vec2 - Compare by value (~= also works)
vec:length() - Length (sqrt(x^2 + y^2 + z^2))
vec:normalize() - Preserve direction but scale so magnitude is 1
vec:floor() - Floor each element
vec:ceil() - Ceil each element
vec:abs() - Absolute value each element
vec1:dot(vec2) - Dot product
vec1:cross(vec2) - Cross product (Only defined for two vectors of length 3)
vec:rotateZ(radians) - Rotate counterclockwise about the Z (vertical) axis
vec:rotateByAngleId(0/1/2/3) - Rotate counterclockwise about the Z (vertical) axis in increments of 90 degrees
vec:tsString() - Convert to string usable by Torque. Done automatically when a vector is passed to Torque.
vec1:distance(vec2) - Distance between two points
vec2 = vec:copy() - Clone a vector so its elements can be modified without affecting the original. Usually not needed - the builtin vector functions never modify vectors in-place.
Extended Standard Lua Library
table.empty - True if the table contains no non-nil values
table.map(func, ...) - Apply func to each set of elements in the given lists, and return a list of results
table.map_pairs(func, ...) - Apply func to each set of elements in the given dict-tables, and return a dict of results
table.swap(tbl) - Swap keys and values
table.reverse(list) - Reverse the order of a list
table.islist(list) - True if the table contains only monotonic integer keys
table.append(list, ...) - Append the contents of the subsequent lists to list in-place
table.join(...) - Return a new list containing the concatenation of all given lists
table.sub(t, a,b) - Return a slice of the given list, similar to string.sub
table.contains(list, val) - True if the list contains val as a value
table.contains_pairs(tbl, val) - True if the table contains val as a value
table.copy(list) - Return a new (shallow) copy of the list
table.copy_pairs(tbl) - Return a new (shallow) copy of the table
table.sortcopy(tbl, sortFunction=a<b) - Return a new sorted (shallow) copy of the table, similar to table.sort
table.removevalue(list, val) - Remove a value from a list, shifting subsequent elements down
table.removevalue_pairs(list, val) - Remove a value from a dict
table.tostring(tbl, multiline=false) - Convert a table into a string representation, optionally breaking into multiple lines
string.split(str, separator='' (splits into chars), noregex=false) - Return a table of substrings, which may be empty if two separators are adjacent
string.bytes(str) - Convert into a table of bytes
string.trim(str, charsToTrim=' \t\r\n') - Remove leading and trailing whitespace
for char in str:chars() do - Iterate characters in a string
string.escape(str, escapes={['\n']='\\n', etc. (ANSI standard plus \x##)}) - Add escape sequences for non-printable characters
string.unescape(str, escapeChar='\\', unescapes={['\\n']='\n', etc.}) - Contract escape sequences in a string to their real characters
io.readfile(filename) - Return the contents of a file, or nil if it does not exist
io.writefile(filename, str) - Create/overwrite a file with the given contents
math.round(num) - Round to nearest whole number, 0.5 rounds up
math.mod(divisor, modulus) - Algebraic modulo with correct behavior for decimals and negatives
math.clamp(num, min, max) - Limit a value within a range
Type Conversion
When a TorqueScript function is called from Lua or vice-versa, the arguments and return value must be converted between the two languages' type systems.
TorqueScript stores no type information; all values in TorqueScript are strings. So it's necessary to make some assumptions when converting values between the two languages.
From Lua to TorqueScript
nilbecomes an empty string ""trueandfalsebecome "1" and "0" respectively- A Torque object container becomes its object ID
- A
vectorbecomes a string containing three numbers separated by spaces - A table of two
vectors becomes a string containing six numbers separated by spaces - (WIP) A
matrixis converted into an axis-angle (a "transform"), a string containing seven numbers separated by spaces - Any
stringis passed directly as a string - Tables cannot be passed and will throw an error
From TorqueScript to Lua
- An empty string "" becomes
nil - Any numeric value becomes a Lua
number, except as specified withbl.type, which may convert a value into abooleanor a Torque object reference. - A string containing two or three numbers separated by single spaces becomes a
vector - A string containing six numbers separated by single spaces becomes a table of two 3-
vectors, often used in Torque to represent the corners a bounding box - (WIP) A string containing seven numbers separated by single spaces is treated as a vector+axis-angle combination (a "transform"), and is converted into a
matrixrepresenting the translation and rotation - Any other string is passed directly as a
string
For scenarios where the automatic TorqueScript->Lua conversion rules are insufficient or incorrect, use bl.type.
To convert things by hand, use bl.object, bl.boolean, or bl.string.
I/O and Safety
All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is.
BlockLua also has access to any C libraries installed in the modules/lualib folder, so be careful throwing things in there.
Unsafe Mode
BlockLua can be built with the compiler flag -DBLLUA_ALLOWFFI to allow the use of the ffi and debug libraries, as well as luahooks32 if installed.
These features can be used to escape the sandbox, and should only be enabled by advanced users. No binary is provided for this mode.
Compiling
With any 32-bit variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
g++ src/bllua4.cpp -o BlockLua.dll -m32 -shared -static-libgcc -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/