improve readme, improve std lib
This commit is contained in:
BIN
BlockLua.dll
BIN
BlockLua.dll
Binary file not shown.
@@ -6,11 +6,11 @@ set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -
|
||||
echo on
|
||||
|
||||
g++ src/bllua4.cpp %buildargs% -o BlockLua.dll
|
||||
@rem && g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll
|
||||
|
||||
@rem objdump -d BlockLua.dll > BlockLua.dll.dump.txt
|
||||
@rem objdump -d BlockLua-Unsafe.dll > BlockLua-Unsafe.dll.dump.txt
|
||||
@rem g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll
|
||||
|
||||
@echo off
|
||||
|
||||
rem objdump -d BlockLua.dll > BlockLua.dll.dump.txt
|
||||
rem objdump -d BlockLua-Unsafe.dll > BlockLua-Unsafe.dll.dump.txt
|
||||
|
||||
pause
|
||||
|
||||
135
readme.md
135
readme.md
@@ -37,7 +37,7 @@ Lua scripting for Blockland
|
||||
`object[index]` - Access a member of a Torque set or group
|
||||
`for childIndex, child in object:members() do` - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
|
||||
|
||||
### Advanced
|
||||
### Timing/Schedules
|
||||
`sched = bl.schedule(timeMs, function, args...)` - Schedule a Lua function to be called later, similar to schedule in Torque
|
||||
`sched:cancel()` - Cancel a previously scheduled timer
|
||||
|
||||
@@ -47,14 +47,14 @@ Lua scripting for Blockland
|
||||
`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.
|
||||
|
||||
### Server-Client Communication
|
||||
`bl.addServerCmd('commandName', function(client, args...) code() end)` - Register a /-command on the server
|
||||
`bl.addClientCmd('commandName', function(args...) code() end)` - Register a client command on the client
|
||||
`bl.addServerCmd('commandName', function(client, args...) yourCode end)` - Register a /command on the server
|
||||
`bl.addClientCmd('commandName', function(args...) yourCode end)` - Register a client command on the client
|
||||
`bl.commandToServer('commandName', args...)` - Execute a server command as a client
|
||||
`bl.commandToClient('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) code() end)` - Hook a Torque function with a Lua function.
|
||||
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) yourCode 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.
|
||||
@@ -62,14 +62,20 @@ In an `after` hook, `args._return` is set to the value returned by the parent fu
|
||||
`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
|
||||
|
||||
### Classes and Types
|
||||
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', and nil (default is nil, which 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('className::funcName', 'type')` - Register the return type of a Torque object method.
|
||||
`bl.class('className')` - Register a Torque class to be used from Lua (Already done for all built-in classes)
|
||||
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
||||
`bl.bool(thing)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
|
||||
`bl.object(thing)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
|
||||
### 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.lua`
|
||||
- `modulePath/moduleName.lua` (Relative to game directory)
|
||||
- `modulePath/moduleName/init.lua` (Relative to game directory)
|
||||
- `modules/lualib/modulePath/moduleName.lua`
|
||||
- `modules/lualib/modulePath/moduleName/init.lua`
|
||||
- `modules/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. To allow hot reloading, use `dofile`.
|
||||
|
||||
### File I/O
|
||||
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
|
||||
@@ -81,27 +87,78 @@ Relative paths (`./`) are allowed. `..` is not allowed.
|
||||
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 from outside ZIPs, binary files are fully supported.
|
||||
|
||||
### Modules and Dependencies
|
||||
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
|
||||
### 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
|
||||
|
||||
`require('modulePath.moduleName')` - Load a Lua file or or external library.
|
||||
Require replaces `.` with `/` in the path, and then searches for files in the following order:
|
||||
- `./modulePath/moduleName.lua`
|
||||
- `./modulePath/moduleName/init.lua`
|
||||
- `modulePath/moduleName.lua` (Relative to game directory)
|
||||
- `modulePath/moduleName/init.lua` (Relative to game directory)
|
||||
- `modules/lualib/modulePath/moduleName.lua`
|
||||
- `modules/lualib/modulePath/moduleName/init.lua`
|
||||
- `modules/lualib/modulePath/moduleName.dll`
|
||||
### Classes and Types
|
||||
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', and nil (default is nil, which 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('className::funcName', 'type')` - Register the return type of a Torque object method.
|
||||
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
|
||||
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
||||
`bl.boolean(thing)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
|
||||
`bl.object(thing)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
|
||||
|
||||
Like in standard Lua, modules loaded using `require` are only executed the first time `require` is called with that path. Subsequent calls simply return the result from the initial execution. To allow hot reloading, use `dofile`.
|
||||
### Vectors
|
||||
`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
|
||||
`vec:length()` - Length
|
||||
`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.
|
||||
|
||||
### TBD
|
||||
- bl.class
|
||||
- bl.new
|
||||
- bl.datablock
|
||||
- vector
|
||||
- Extended standard library functions
|
||||
### Extended Standard Lua Library
|
||||
`string[index]`
|
||||
`string[{start,stop}]`
|
||||
`string.split(str, separator='' (splits into chars), noregex=false)`
|
||||
`string.bytes(str)`
|
||||
`string.trim(str, charsToTrim=' \t\r\n')`
|
||||
`table.empty`
|
||||
`table.map(func, ...)`
|
||||
`table.map_list(func, ...)`
|
||||
`table.swap(tbl)`
|
||||
`table.reverse(list)`
|
||||
`table.islist(list)`
|
||||
`table.append(list, ...)`
|
||||
`table.join(...)`
|
||||
`table.contains(tbl, val)`
|
||||
`table.contains_list(list, val)`
|
||||
`table.copy(tbl)`
|
||||
`table.copy_list(list)`
|
||||
`table.sortcopy(tbl, sortFunction?)`
|
||||
`table.removevalue(tbl, val)`
|
||||
`table.removevalue_list(tbl, val)`
|
||||
`table.tostring(tbl)`
|
||||
`for char in string.chars(str) do`
|
||||
`string.escape(str, escapes={['\n']='\\n', etc. (C standard)})`
|
||||
`string.unescape(str, escapeChar='\\', unescapes={['\\n']='\n', etc.})`
|
||||
`io.readall(filename)`
|
||||
`io.writeall(filename, str)`
|
||||
`math.round(num)`
|
||||
`math.mod(divisor, modulus)`
|
||||
`math.clamp(num, min, max)`
|
||||
|
||||
## 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.
|
||||
@@ -125,17 +182,17 @@ TorqueScript stores no type information; all values in TorqueScript are strings.
|
||||
All Lua code is sandboxed, and file access is confied 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-Unsafe.dll can be used in place of BlockLua.dll, to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi.
|
||||
BlockLua-Unsafe.dll can be built and used in place of BlockLua.dll (see compile.bat), to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi.
|
||||
Please do not publish add-ons that require unsafe mode.
|
||||
|
||||
## Other Reference
|
||||
|
||||
### List of Object Types
|
||||
'all' - Any object
|
||||
'brick' - Bricks with Ray-Casting enabled
|
||||
'brickalways' - All bricks including those with Ray-Casting disabled
|
||||
'player' - Players or bots
|
||||
'item' - Items
|
||||
'vehicle' - Vehicles
|
||||
'projectile' - Projectiles
|
||||
Other types: 'static', 'environment', 'terrain', 'water', 'trigger', 'marker', 'gamebase', 'shapebase', 'camera', 'staticshape', 'vehicleblocker', 'explosion', 'corpse', 'debris', 'physicalzone', 'staticts', 'staticrendered', 'damagableitem'
|
||||
`'all'` - Any object
|
||||
`'player'` - Players or bots
|
||||
`'item'` - Items
|
||||
`'vehicle'` - Vehicles
|
||||
`'projectile'` - Projectiles
|
||||
`'brick'` - Bricks 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'`
|
||||
|
||||
@@ -536,7 +536,7 @@ end
|
||||
function bl.exec(file)
|
||||
return valFromTs(_bllua_ts.call('exec', file))
|
||||
end
|
||||
function bl.tobool(val)
|
||||
function bl.boolean(val)
|
||||
return val~=nil and
|
||||
val~=false and
|
||||
--val~='' and
|
||||
@@ -734,6 +734,9 @@ function bl.hook(pkg, name, time, func)
|
||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||
activatePackage(pkg)
|
||||
end
|
||||
local function tableEmpty(t)
|
||||
return next(t)~=nil
|
||||
end
|
||||
function bl.unhook(pkg, name, time)
|
||||
if not isValidFuncName(pkg) then
|
||||
error('bl.unhook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
||||
@@ -766,7 +769,7 @@ function bl.unhook(pkg, name, time)
|
||||
if time~='before' and time~='after' then
|
||||
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2) end
|
||||
bl._hooks[pkg][name][time] = nil
|
||||
if table.empty(bl._hooks[pkg][name]) and table.empty(bl._hooks[pkg]) then
|
||||
if tableEmpty(bl._hooks[pkg][name]) and tableEmpty(bl._hooks[pkg]) then
|
||||
bl._hooks[pkg] = nil
|
||||
deactivatePackage(pkg)
|
||||
updateHook(pkg, name, {})
|
||||
@@ -871,10 +874,15 @@ function bl.radiusSearch(pos, radius, mask)
|
||||
end
|
||||
|
||||
-- Print/Talk/Echo
|
||||
local maxTsArgLen = 8192
|
||||
local function valsToString(vals)
|
||||
local strs = {}
|
||||
for i,v in ipairs(vals) do
|
||||
strs[i] = table.tostring(v)
|
||||
local tstr = table.tostring(v)
|
||||
if #tstr>maxTsArgLen then
|
||||
tstr = tostring(v)
|
||||
end
|
||||
strs[i] = tstr
|
||||
end
|
||||
return table.concat(strs, ' ')
|
||||
end
|
||||
@@ -889,11 +897,12 @@ bl.talk = function(...)
|
||||
_bllua_ts.call('talk', str)
|
||||
end
|
||||
|
||||
-- bl.new and bl.datablock
|
||||
local function createTsObj(keyword, class, name, inherit, props)
|
||||
local propsT = {}
|
||||
for k,v in pairs(props) do
|
||||
if not isValidFuncName(k) then
|
||||
error('bl.new/datablock: invalid property name \''..k..'\'') end
|
||||
error('bl.new/bl.datablock: invalid property name \''..k..'\'') end
|
||||
table.insert(propsT, k..'="'..valToTs(v)..'";')
|
||||
end
|
||||
|
||||
@@ -903,7 +912,7 @@ local function createTsObj(keyword, class, name, inherit, props)
|
||||
table.concat(propsT)..'};')
|
||||
local obj = toTsObject(objS)
|
||||
if not obj then
|
||||
error('bl.new/datablock: failed to create object', 3) end
|
||||
error('bl.new/bl.datablock: failed to create object', 3) end
|
||||
|
||||
return obj
|
||||
end
|
||||
@@ -926,7 +935,7 @@ local function parseTsDecl(decl)
|
||||
isValidFuncName(class) and
|
||||
(name==nil or isValidFuncName(name)) and
|
||||
(inherit==nil or isValidFuncName(inherit)) ) then
|
||||
error('bl.new/datablock: invalid decl \''..decl..'\'\n'..
|
||||
error('bl.new/bl.datablock: invalid decl \''..decl..'\'\n'..
|
||||
'must be of the format: \'className\', \'className name\', '..
|
||||
'\'className :inherit\', or \'className name:inherit\'', 3) end
|
||||
return class, name, inherit
|
||||
@@ -937,6 +946,7 @@ function bl.new(decl, props)
|
||||
end
|
||||
function bl.datablock(decl, props)
|
||||
local class, name, inherit = parseTsDecl(decl)
|
||||
if not name then error('bl.datablock: must specify a name', 2) end
|
||||
return createTsObj('datablock', class, name, inherit, props)
|
||||
end
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
-- Table / List
|
||||
-- Whether a table contains no keys
|
||||
function table.empty(t)
|
||||
for _,_ in pairs(t) do return false end
|
||||
return true
|
||||
return next(t)~=nil
|
||||
end
|
||||
-- Apply a function to each key in a table
|
||||
function table.map(f, ...)
|
||||
@@ -41,18 +40,6 @@ function table.reverse(l)
|
||||
for i=1,#l do m[#l-i+1] = l[i] end
|
||||
return m
|
||||
end
|
||||
-- Convert i->v to v->true
|
||||
function table.values(l)
|
||||
local u = {}
|
||||
for _,v in ipairs(l) do u[v] = true end
|
||||
return u
|
||||
end
|
||||
-- Make a list of keys
|
||||
function table.keys(t)
|
||||
local u = {}
|
||||
for k,_ in pairs(t) do table.insert(u, k) end
|
||||
return u
|
||||
end
|
||||
-- Whether a table is a list/array (has only monotonic integer keys)
|
||||
function table.islist(t)
|
||||
local n = 0
|
||||
@@ -244,8 +231,8 @@ function string.bytes(s)
|
||||
end
|
||||
-- Trim leading and trailing whitespace
|
||||
function string.trim(s, ws)
|
||||
ws = ws or '[ \t\r\t]'
|
||||
return s:gsub('^'..ws..'+', ''):gsub(ws..'+$', '')..''
|
||||
ws = ws or ' \t\r\n'
|
||||
return s:gsub('^['..ws..']+', ''):gsub('['..ws..']+$', '')..''
|
||||
end
|
||||
-- String slicing and searching using [] operator
|
||||
local str_meta = getmetatable('')
|
||||
@@ -325,7 +312,7 @@ end
|
||||
|
||||
io = io or {}
|
||||
-- Read entire file at once, return nil,err if access failed
|
||||
function io.readfile(filename)
|
||||
function io.readall(filename)
|
||||
local fi,err = io.open(filename, 'rb')
|
||||
if not fi then return nil,err end
|
||||
local s = fi:read("*a")
|
||||
@@ -333,7 +320,7 @@ function io.readfile(filename)
|
||||
return s
|
||||
end
|
||||
-- Write data to file all at once, return true if success / false,err if failure
|
||||
function io.writefile(filename, data)
|
||||
function io.writeall(filename, data)
|
||||
local fi,err = io.open(filename, 'wb')
|
||||
if not fi then return false,err end
|
||||
fi:write(data)
|
||||
|
||||
@@ -127,7 +127,7 @@ local vector_meta = {
|
||||
for i = 1, len do
|
||||
table.insert(st, tostring(v1[i]))
|
||||
end
|
||||
return '{ '..table.concat(st, ', ')..' }'
|
||||
return 'vector{ '..table.concat(st, ', ')..' }'
|
||||
end,
|
||||
unpack = function(v1) return unpack(v1) end,
|
||||
floor = vector_opn0n('floor', function(x1) return math.floor(x1) end),
|
||||
@@ -162,10 +162,10 @@ local vector_meta = {
|
||||
else error('vector rotateByAngleId: invalid rotation '..r, 2) end
|
||||
return v2
|
||||
end,
|
||||
rotate2d = function(v, r)
|
||||
rotateZ = function(v, r)
|
||||
--vector_check(v, 2, 'rotate2d')
|
||||
if type(r)~='number' then
|
||||
error('vector rotate2d: invalid rotation '..tostring(r), 2) end
|
||||
error('vector rotateZ: invalid rotation '..tostring(r), 2) end
|
||||
local len = math.sqrt(v[1]^2 + v[2]^2)
|
||||
local ang = math.atan2(v[2], v[1]) + r
|
||||
local v2 = vector_new{ math.cos(ang)*len, math.sin(ang)*len }
|
||||
|
||||
Reference in New Issue
Block a user