forked from redo/BlockLua
Compare commits
6 Commits
ed5c254480
...
5885dcbed3
| Author | SHA1 | Date | |
|---|---|---|---|
| 5885dcbed3 | |||
| d9a416f5d5 | |||
|
|
2191e004ad | ||
|
|
ae34bb8b7a | ||
|
|
b71bfdb73e | ||
|
|
7232ede09d |
BIN
BlockLua.dll
BIN
BlockLua.dll
Binary file not shown.
62
readme.md
62
readme.md
@@ -14,10 +14,10 @@ Lua scripting for Blockland
|
|||||||
### From TorqueScript
|
### From TorqueScript
|
||||||
`'print('hello world')` - Execute Lua in the console by prepending a `'` (single quote)
|
`'print('hello world')` - Execute Lua in the console by prepending a `'` (single quote)
|
||||||
`luaeval("code");` - Execute Lua code
|
`luaeval("code");` - Execute Lua code
|
||||||
`luacall("funcName", %args...);` - Call a Lua global function
|
`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 executing .cs files.
|
`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
|
`luaget("varName");` - Read a Lua global variable (supports indexing tables)
|
||||||
`luaset("varName", %value);` - Write a Lua global variable
|
`luaset("varName", %value);` - Write a Lua global variable (supports indexing tables)
|
||||||
|
|
||||||
### From Lua
|
### From Lua
|
||||||
`bl.eval('code')` - Eval TorqueScript code
|
`bl.eval('code')` - Eval TorqueScript code
|
||||||
@@ -35,7 +35,7 @@ Lua scripting for Blockland
|
|||||||
`object.key = value` - Associate Lua data with a Torque object
|
`object.key = value` - Associate Lua data with a Torque object
|
||||||
`object:method(args)` - Call a Torque object method
|
`object:method(args)` - Call a Torque object method
|
||||||
`object[index]` - Access a member of a Torque set or group
|
`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.
|
`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
|
`bl.isObject(object, objectID, or 'objectName')` - Check if an object exists
|
||||||
`object:exists()` - Check if an object exists
|
`object:exists()` - Check if an object exists
|
||||||
|
|
||||||
@@ -48,15 +48,25 @@ Lua scripting for Blockland
|
|||||||
`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.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.
|
`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 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
|
### Server-Client Communication
|
||||||
`bl.addServerCmd('commandName', function(client, args...) yourCode end)` - Register a /command on the server
|
`bl.addServerCmd('commandName', function(client, args...) ... end)` - Register a /command on the server
|
||||||
`bl.addClientCmd('commandName', function(args...) yourCode end)` - Register a client command on the client
|
`bl.addClientCmd('commandName', function(args...) ... end)` - Register a client command on the client
|
||||||
`bl.commandToServer('commandName', args...)` - Execute a server command as a client
|
`bl.commandToServer('commandName', args...)` - As a client, execute a server command
|
||||||
`bl.commandToClient('commandName', args...)` - As the server, execute a client command on a specific client
|
`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
|
`bl.commandToAll('commandName', args...)` - As the server, execute a client command on all clients
|
||||||
|
|
||||||
### Packages/Hooks
|
### Packages/Hooks
|
||||||
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) yourCode end)` - Hook a Torque function with a Lua function.
|
`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.
|
`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.
|
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.
|
In an `after` hook, `args._return` is set to the value returned by the parent function, and can be modified.
|
||||||
@@ -136,14 +146,16 @@ When reading from outside ZIPs, binary files are fully supported.
|
|||||||
WIP
|
WIP
|
||||||
|
|
||||||
### Extended Standard Lua Library
|
### Extended Standard Lua Library
|
||||||
`string[index]`
|
`str[index]`
|
||||||
`string[{start,stop}]`
|
`str[{start,stop}]`
|
||||||
`string.split(str, separator='' (splits into chars), noregex=false)`
|
`string.split(str, separator='' (splits into chars), noregex=false)`
|
||||||
`string.bytes(str)`
|
`string.bytes(str)`
|
||||||
`string.trim(str, charsToTrim=' \t\r\n')`
|
`string.trim(str, charsToTrim=' \t\r\n')`
|
||||||
`table.empty`
|
`table.empty`
|
||||||
`table.map(func, ...)`
|
`table.map(func, ...)`
|
||||||
|
`table.mapk(func, ...)`
|
||||||
`table.map_list(func, ...)`
|
`table.map_list(func, ...)`
|
||||||
|
`table.mapi_list(func, ...)`
|
||||||
`table.swap(tbl)`
|
`table.swap(tbl)`
|
||||||
`table.reverse(list)`
|
`table.reverse(list)`
|
||||||
`table.islist(list)`
|
`table.islist(list)`
|
||||||
@@ -173,43 +185,35 @@ TorqueScript stores no type information; all values in TorqueScript are strings.
|
|||||||
### From Lua to TorqueScript
|
### From Lua to TorqueScript
|
||||||
- `nil` becomes the empty string ""
|
- `nil` becomes the empty string ""
|
||||||
- `true` and `false` become "1" and "0" respectively
|
- `true` and `false` become "1" and "0" respectively
|
||||||
- Torque containers become their object ID
|
- A Torque object container becomes its object ID
|
||||||
- A `vector` becomes a string containing three numbers separated by spaces
|
- A `vector` becomes a string containing three numbers separated by spaces
|
||||||
- A table of two vectors becomes a string containing six numbers separated by spaces
|
- A table of two `vector`s becomes a string containing six numbers separated by spaces
|
||||||
|
- (WIP) A `matrix` is converted into an axis-angle (a "transform"), a string containing seven numbers separated by spaces
|
||||||
- Any `string` is passed directly as a string
|
- Any `string` is passed directly as a string
|
||||||
- Tables cannot be passed and will throw an error
|
- Tables cannot be passed and will throw an error
|
||||||
|
|
||||||
### From TorqueScript to Lua
|
### From TorqueScript to Lua
|
||||||
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
|
|
||||||
- The empty string "" becomes `nil`
|
- The empty string "" becomes `nil`
|
||||||
|
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
|
||||||
- A string containing two or three numbers separated by single spaces becomes a `vector`
|
- 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 vectors, usually defining the corners a bounding box
|
- A string containing six numbers separated by single spaces becomes a table of two vectors, usually defining the corners a bounding box
|
||||||
- (WIP) A string containing seven numbers separated by single spaces is treated as an axis-angle (a "transform" in TorqueScript parlance), and is converted into a `matrix` representing the translation and rotation.
|
- (WIP) A string containing seven numbers separated by single spaces is treated as an axis-angle (a "transform"), and is converted into a `matrix` representing the translation and rotation
|
||||||
- Any other string is passed directly as a `string`
|
- 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`.
|
For scenarios where the automatic TorqueScript->Lua conversion rules are insufficient or incorrect, use `bl.type`.
|
||||||
To convert objects by hand, use `bl.object`, `bl.boolean`, or `bl.string`.
|
To convert things by hand, use `bl.object`, `bl.boolean`, or `bl.string`.
|
||||||
|
|
||||||
## I/O and Safety
|
## I/O and Safety
|
||||||
All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is.
|
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.
|
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
|
||||||
### Unsafe Mode
|
### Unsafe Mode
|
||||||
BlockLua can be built in Unsafe Mode by specifying the `-DBLLUA_UNSAFE` compiler flag. This removes the sandboxing of Lua code, allowing it to access any file and use any library, including ffi.
|
BlockLua can be built in Unsafe Mode by specifying the `-DBLLUA_UNSAFE` compiler flag. This removes the sandboxing of Lua code, allowing it to access any file and use any library, including ffi.
|
||||||
Please do not publish add-ons that require unsafe mode.
|
A more limited option is `-DBLLUA_ALLOWFFI`, which allows the use of the `ffi` library. This can still be exploited to grant all the same access as full unsafe mode.
|
||||||
|
Please do not publish add-ons that require either of these.
|
||||||
### List of Object Types
|
|
||||||
`'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'`
|
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
||||||
With any *32-bit* variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
|
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 src/bllua`
|
`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/
|
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// BlockLua (bllua4): Simple Lua interface for TorqueScript
|
// BlockLua (bllua4): Advanced Lua interface for TorqueScript
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
|
|
||||||
@@ -60,23 +60,27 @@ bool init() {
|
|||||||
|
|
||||||
// Set up Lua environment
|
// Set up Lua environment
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaEnv);
|
BLL_LOAD_LUA(gL, bll_fileLuaEnv);
|
||||||
|
#ifdef BLLUA_ALLOWFFI
|
||||||
|
lua_pushboolean(gL, true);
|
||||||
|
lua_setglobal(gL, "_bllua_allowffi");
|
||||||
|
#endif
|
||||||
#ifndef BLLUA_UNSAFE
|
#ifndef BLLUA_UNSAFE
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaEnvSafe);
|
BLL_LOAD_LUA(gL, bll_fileLuaEnvSafe);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Load utilities in Lua
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaMatrix);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
||||||
|
|
||||||
// Expose Lua API to TS
|
// Expose Lua API to TS
|
||||||
BlAddFunction(
|
BlAddFunction(
|
||||||
NULL, NULL, "_bllua_luacall", bll_ts_luacall, "LuaCall(name, ...) - Call Lua function and return result", 2, 20);
|
NULL, NULL, "_bllua_luacall", bll_ts_luacall, "LuaCall(name, ...) - Call Lua function and return result", 2, 20);
|
||||||
BlEval(bll_fileTsEnv);
|
BlEval(bll_fileTsEnv);
|
||||||
|
|
||||||
// Load utilities
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaMatrix);
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
|
||||||
BlEval(bll_fileTsLibts);
|
BlEval(bll_fileTsLibts);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
|
||||||
BlEval(bll_fileTsLibblSupport);
|
BlEval(bll_fileTsLibblSupport);
|
||||||
BlEval(bll_fileLoadaddons);
|
BlEval(bll_fileLoadaddons);
|
||||||
|
|
||||||
@@ -89,8 +93,7 @@ bool init() {
|
|||||||
bool deinit() {
|
bool deinit() {
|
||||||
BlPrintf("BlockLua: Unloading");
|
BlPrintf("BlockLua: Unloading");
|
||||||
|
|
||||||
BlEval("deactivatePackage(_bllua_main);");
|
BlEval("$_bllua_active=0;deactivatePackage(_bllua_main);");
|
||||||
BlEval("$_bllua_active = 0;");
|
|
||||||
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
||||||
|
|
||||||
lua_close(gL);
|
lua_close(gL);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ local old_require = require
|
|||||||
local old_os = os
|
local old_os = os
|
||||||
local old_debug = debug
|
local old_debug = debug
|
||||||
local old_package = package
|
local old_package = package
|
||||||
|
local old_allowffi = _bllua_allowffi
|
||||||
|
|
||||||
-- Remove all global variables except a whitelist
|
-- Remove all global variables except a whitelist
|
||||||
local ok_names = tmap {
|
local ok_names = tmap {
|
||||||
@@ -39,13 +40,10 @@ end
|
|||||||
|
|
||||||
-- Sanitize file paths to point only to allowed files within the game directory
|
-- Sanitize file paths to point only to allowed files within the game directory
|
||||||
-- List of allowed directories for reading/writing
|
-- List of allowed directories for reading/writing
|
||||||
|
-- modules/lualib is also allowed as read-only
|
||||||
local allowed_dirs = tmap {
|
local allowed_dirs = tmap {
|
||||||
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
||||||
}
|
}
|
||||||
-- List of allowed directories for reading only
|
|
||||||
local allowed_dirs_readonly = tmap {
|
|
||||||
'lualib'
|
|
||||||
}
|
|
||||||
-- List of disallowed file extensions - basically executable file extensions
|
-- List of disallowed file extensions - basically executable file extensions
|
||||||
-- Note that even without this protection, exploiting would still require somehow
|
-- Note that even without this protection, exploiting would still require somehow
|
||||||
-- getting a file within the allowed directories to autorun,
|
-- getting a file within the allowed directories to autorun,
|
||||||
@@ -81,14 +79,15 @@ local function safe_path(fn, readonly)
|
|||||||
end
|
end
|
||||||
-- allow only whitelisted dirs
|
-- allow only whitelisted dirs
|
||||||
local dir = fn:match('^([^/]+)/')
|
local dir = fn:match('^([^/]+)/')
|
||||||
if (not dir) or (
|
if not (dir and (
|
||||||
(not allowed_dirs[dir:lower()]) and
|
allowed_dirs[dir:lower()] or
|
||||||
((not readonly) or (not allowed_dirs_readonly[dir:lower()]))) then
|
(readonly and fn:find('^modules/lualib/'))))
|
||||||
return nil, 'filename is in disallowed directory ' .. (dir or 'nil')
|
then
|
||||||
|
return nil, 'File is in disallowed directory ' .. (dir or 'nil')
|
||||||
end
|
end
|
||||||
-- disallow blacklisted extensions or no extension
|
-- disallow blacklisted extensions
|
||||||
local ext = fn:match('%.([^/%.]+)$')
|
local ext = fn:match('%.([^/%.]+)$')
|
||||||
if (not ext) or (disallowed_exts[ext:lower()]) then
|
if ext and disallowed_exts[ext:lower()] then
|
||||||
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
|
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
|
||||||
(ext or '') .. '\''
|
(ext or '') .. '\''
|
||||||
end
|
end
|
||||||
@@ -120,6 +119,7 @@ local disallowed_packages = tmap {
|
|||||||
'ffi', 'debug', 'package', 'io', 'os',
|
'ffi', 'debug', 'package', 'io', 'os',
|
||||||
'_bllua_ts',
|
'_bllua_ts',
|
||||||
}
|
}
|
||||||
|
if old_allowffi then disallowed_packages['ffi'] = nil end
|
||||||
function _bllua_requiresecure(name)
|
function _bllua_requiresecure(name)
|
||||||
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
|
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
|
||||||
name:find('^%.') or name:find('%.$') then
|
name:find('^%.') or name:find('%.$') then
|
||||||
|
|||||||
@@ -37,5 +37,9 @@ function _bllua_on_error(err)
|
|||||||
return table.concat(tracelines, '\n')
|
return table.concat(tracelines, '\n')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- overridden in lua-env-safe.lua (executed if not BLLUA_UNSAFE)
|
||||||
|
_bllua_io_open = io.open
|
||||||
|
_bllua_requiresecure = require
|
||||||
|
|
||||||
print = _bllua_ts.echo
|
print = _bllua_ts.echo
|
||||||
print(' Executed bllua-env.lua')
|
print(' Executed bllua-env.lua')
|
||||||
|
|||||||
@@ -6,15 +6,33 @@ local _bllua_ts = ts
|
|||||||
|
|
||||||
bl = bl or {}
|
bl = bl or {}
|
||||||
|
|
||||||
|
-- Config
|
||||||
|
local tsMaxArgs = 16
|
||||||
|
local tsArgsLocal = '%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p'
|
||||||
|
local tsArgsGlobal =
|
||||||
|
'$_bllua_hook_arg1,$_bllua_hook_arg2,$_bllua_hook_arg3,$_bllua_hook_arg4,' ..
|
||||||
|
'$_bllua_hook_arg5,$_bllua_hook_arg6,$_bllua_hook_arg7,$_bllua_hook_arg8,' ..
|
||||||
|
'$_bllua_hook_arg9,$_bllua_hook_arg10,$_bllua_hook_arg11,$_bllua_hook_arg12,' ..
|
||||||
|
'$_bllua_hook_arg13,$_bllua_hook_arg14,$_bllua_hook_arg15,$_bllua_hook_arg16'
|
||||||
|
|
||||||
-- Misc
|
-- Misc
|
||||||
-- Apply a function to each element in a list, building a new list from the returns
|
local function ipairsNilable(t)
|
||||||
local function map(t,f)
|
local maxk = 0
|
||||||
local u = {}
|
for k, _ in pairs(t) do
|
||||||
for i,v in ipairs(t) do
|
if k > maxk then maxk = k end
|
||||||
u[i] = f(v)
|
|
||||||
end
|
end
|
||||||
return u
|
local i = 0
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
if i > maxk then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return i, t[i]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Validation
|
||||||
local function isValidFuncName(name)
|
local function isValidFuncName(name)
|
||||||
return type(name) == 'string' and name:find('^[a-zA-Z_][a-zA-Z0-9_]*$')
|
return type(name) == 'string' and name:find('^[a-zA-Z_][a-zA-Z0-9_]*$')
|
||||||
end
|
end
|
||||||
@@ -107,27 +125,34 @@ end
|
|||||||
|
|
||||||
-- Type conversion from TS to Lua
|
-- Type conversion from TS to Lua
|
||||||
local fromTsForceTypes = {
|
local fromTsForceTypes = {
|
||||||
['boolean'] = tsBool,
|
['boolean'] = function(val) return tsBool(val) end,
|
||||||
['object'] = function(val) toTsObject(val) end, -- wrap because toTsObject not defined yet
|
['object'] = function(val) return toTsObject(val) end, -- wrap because toTsObject not defined yet
|
||||||
['string'] = function(val) return val end,
|
['string'] = function(val) return val end,
|
||||||
}
|
}
|
||||||
local function forceValFromTs(val, typ)
|
local function forceValFromTs(val, typ)
|
||||||
return fromTsForceTypes[typ](val) or
|
local func = fromTsForceTypes[typ]
|
||||||
error('valFromTs: invalid force type '..typ, 4)
|
if not func then error('valFromTs: invalid force type \'' .. typ .. '\'', 4) end
|
||||||
|
return func(val)
|
||||||
end
|
end
|
||||||
local function vectorFromTs(val)
|
local function vectorFromTs(val)
|
||||||
local xS, yS, zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
local xS, yS, zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
||||||
if xS then return vector{tonumber(xS),tonumber(yS),tonumber(zS)}
|
if xS then
|
||||||
else return nil end
|
return vector { tonumber(xS), tonumber(yS), tonumber(zS) }
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local function boxFromTs(val)
|
local function boxFromTs(val)
|
||||||
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
|
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
|
||||||
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
|
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
|
||||||
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
||||||
if x1S then return {
|
if x1S then
|
||||||
|
return {
|
||||||
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
|
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
|
||||||
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
|
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
|
||||||
else return nil end
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local function multinumericFromTs(val)
|
local function multinumericFromTs(val)
|
||||||
local tsNumPat = '%-?[0-9]+%.?[0-9]*e?[0-9]*'
|
local tsNumPat = '%-?[0-9]+%.?[0-9]*e?[0-9]*'
|
||||||
@@ -154,9 +179,11 @@ local function multinumericFromTs(val)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
bl._forceType = bl._forceType or {}
|
bl._forceType = bl._forceType or {}
|
||||||
local function valFromTs(val, name, name2) -- todo: ensure name and name2 are already lowercase
|
-- todo: ensure name and name2 are already lowercase
|
||||||
|
local function valFromTs(val, name, name2)
|
||||||
if type(val) ~= 'string' then
|
if type(val) ~= 'string' then
|
||||||
error('valFromTs: expected string, got '..type(val), 3) end
|
error('valFromTs: expected string, got ' .. type(val), 3)
|
||||||
|
end
|
||||||
if name then
|
if name then
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
if bl._forceType[name] then
|
if bl._forceType[name] then
|
||||||
@@ -177,31 +204,42 @@ local function valFromTs(val, name, name2) -- todo: ensure name and name2 are al
|
|||||||
-- vector, box, or axis->matrix
|
-- vector, box, or axis->matrix
|
||||||
local vec = multinumericFromTs(val)
|
local vec = multinumericFromTs(val)
|
||||||
if vec then return vec end
|
if vec then return vec end
|
||||||
|
-- net string
|
||||||
|
if val:sub(1, 1) == '\x01' then
|
||||||
|
return _bllua_ts.call('getTaggedString', val)
|
||||||
|
end
|
||||||
-- string
|
-- string
|
||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
local function arglistFromTs(name, argsS)
|
local function arglistFromTs(name, argsS)
|
||||||
local args = {}
|
local args = {}
|
||||||
for i,arg in ipairs(argsS) do
|
for i, arg in ipairsNilable(argsS) do
|
||||||
args[i] = valFromTs(arg, name .. ':' .. i)
|
args[i] = valFromTs(arg, name .. ':' .. i)
|
||||||
end
|
end
|
||||||
return args
|
return args
|
||||||
end
|
end
|
||||||
local function arglistToTs(args)
|
local function arglistToTs(args)
|
||||||
return map(args, valToTs)
|
local argsS = {}
|
||||||
|
for i, v in ipairsNilable(args) do
|
||||||
|
table.insert(argsS, valToTs(v))
|
||||||
|
end
|
||||||
|
return argsS
|
||||||
end
|
end
|
||||||
local function classFromForceTypeStr(name)
|
local function classFromForceTypeStr(name)
|
||||||
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||||
if not class then
|
if not class then
|
||||||
class, rest = name:match('^([a-zA-Z0-9_]+)(%..+)$') end
|
class, rest = name:match('^([a-zA-Z0-9_]+)(%..+)$')
|
||||||
|
end
|
||||||
return class, rest
|
return class, rest
|
||||||
end
|
end
|
||||||
local setForceType
|
local setForceType
|
||||||
setForceType = function(ftname, typ)
|
setForceType = function(ftname, typ)
|
||||||
if typ ~= nil and not fromTsForceTypes[typ] then
|
if typ ~= nil and not fromTsForceTypes[typ] then
|
||||||
error('bl.type: invalid type \''..typ..'\'', 2) end
|
error('bl.type: invalid type \'' .. typ .. '\'', 2)
|
||||||
|
end
|
||||||
if not isValidFuncNameNsArgn(ftname) then
|
if not isValidFuncNameNsArgn(ftname) then
|
||||||
error('bl.type: invalid function or variable name \''..ftname..'\'', 2) end
|
error('bl.type: invalid function or variable name \'' .. ftname .. '\'', 2)
|
||||||
|
end
|
||||||
|
|
||||||
ftname = ftname:lower()
|
ftname = ftname:lower()
|
||||||
|
|
||||||
@@ -252,15 +290,19 @@ local function tsIsFunction(name) return tsBool(_bllua_ts.call('isFunction', nam
|
|||||||
local function tsIsFunctionNs(ns, name) return tsBool(_bllua_ts.call('isFunction', ns, name)) end
|
local function tsIsFunctionNs(ns, name) return tsBool(_bllua_ts.call('isFunction', ns, name)) end
|
||||||
local function tsIsFunctionNsname(nsname)
|
local function tsIsFunctionNsname(nsname)
|
||||||
local ns, name = nsname:match('^([^:]+)::([^:]+)$')
|
local ns, name = nsname:match('^([^:]+)::([^:]+)$')
|
||||||
if ns then return tsIsFunctionNs(ns, name)
|
if ns then
|
||||||
else return tsIsFunction(nsname) end
|
return tsIsFunctionNs(ns, name)
|
||||||
|
else
|
||||||
|
return tsIsFunction(nsname)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- sanity check to make sure objects that don't isObject are always marked as ._deleted
|
-- sanity check to make sure objects that don't isObject are always marked as ._deleted
|
||||||
-- can be removed later
|
-- can be removed later
|
||||||
local function assertTsObjectExists(obj)
|
local function assertTsObjectExists(obj)
|
||||||
local is = tsIsObject(obj._tsObjectId)
|
local is = tsIsObject(obj._tsObjectId)
|
||||||
if not is then
|
if not is then
|
||||||
print('Warning: TS object :exists or isobject from lua but no longer exists') end
|
print('Warning: TS object :exists or isobject from lua but no longer exists')
|
||||||
|
end
|
||||||
return is
|
return is
|
||||||
end
|
end
|
||||||
function bl.isObject(obj)
|
function bl.isObject(obj)
|
||||||
@@ -278,6 +320,7 @@ function bl.isObject(obj)
|
|||||||
error('bl.isObject: argument #1: expected torque object, number, or string', 2)
|
error('bl.isObject: argument #1: expected torque object, number, or string', 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.isFunction(name)
|
function bl.isFunction(name)
|
||||||
return tsIsFunctionNsname(name)
|
return tsIsFunctionNsname(name)
|
||||||
end
|
end
|
||||||
@@ -292,9 +335,11 @@ local tsClassMeta = {
|
|||||||
bl._objectUserMetas = bl._objectUserMetas or {}
|
bl._objectUserMetas = bl._objectUserMetas or {}
|
||||||
function bl.class(cname, inhname)
|
function bl.class(cname, inhname)
|
||||||
if not (type(cname) == 'string' and isValidFuncName(cname)) then
|
if not (type(cname) == 'string' and isValidFuncName(cname)) then
|
||||||
error('bl.class: argument #1: invalid class name', 2) end
|
error('bl.class: argument #1: invalid class name', 2)
|
||||||
|
end
|
||||||
if not (inhname == nil or (type(inhname) == 'string' and isValidFuncName(inhname))) then
|
if not (inhname == nil or (type(inhname) == 'string' and isValidFuncName(inhname))) then
|
||||||
error('bl.class: argument #2: inherit name must be a string or nil', 2) end
|
error('bl.class: argument #2: inherit name must be a string or nil', 2)
|
||||||
|
end
|
||||||
cname = cname:lower()
|
cname = cname:lower()
|
||||||
|
|
||||||
local met = bl._objectUserMetas[cname] or {
|
local met = bl._objectUserMetas[cname] or {
|
||||||
@@ -309,15 +354,18 @@ function bl.class(cname, inhname)
|
|||||||
inhname = inhname:lower()
|
inhname = inhname:lower()
|
||||||
|
|
||||||
local inh = bl._objectUserMetas[inhname]
|
local inh = bl._objectUserMetas[inhname]
|
||||||
if not inh then error('bl.class: argument #2: \''..inhname..'\' is not the '..
|
if not inh then
|
||||||
'name of an existing class', 2) end
|
error('bl.class: argument #2: \'' .. inhname .. '\' is not the ' ..
|
||||||
|
'name of an existing class', 2)
|
||||||
|
end
|
||||||
|
|
||||||
inh._children[cname] = true
|
inh._children[cname] = true
|
||||||
|
|
||||||
local inhI = met._inherit
|
local inhI = met._inherit
|
||||||
if inhI and inhI ~= inh then
|
if inhI and inhI ~= inh then
|
||||||
error('bl.class: argument #2: class already exists and ' ..
|
error('bl.class: argument #2: class already exists and ' ..
|
||||||
'inherits a different parent.', 2) end
|
'inherits a different parent.', 2)
|
||||||
|
end
|
||||||
met._inherit = inh
|
met._inherit = inh
|
||||||
|
|
||||||
-- apply inherited method and field types
|
-- apply inherited method and field types
|
||||||
@@ -329,6 +377,7 @@ function bl.class(cname, inhname)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function objectInheritedMetas(name)
|
local function objectInheritedMetas(name)
|
||||||
local inh = bl._objectUserMetas[name:lower()]
|
local inh = bl._objectUserMetas[name:lower()]
|
||||||
return function()
|
return function()
|
||||||
@@ -343,15 +392,18 @@ local tsObjectMeta = {
|
|||||||
-- Return torque member function or value
|
-- Return torque member function or value
|
||||||
__index = function(t, name)
|
__index = function(t, name)
|
||||||
if rawget(t, '_deleted') then
|
if rawget(t, '_deleted') then
|
||||||
error('ts object index: object no longer exists', 2) end
|
error('ts object index: object no longer exists', 2)
|
||||||
|
end
|
||||||
if type(name) ~= 'string' and type(name) ~= 'number' then
|
if type(name) ~= 'string' and type(name) ~= 'number' then
|
||||||
error('ts object index: index must be a string or number', 2) end
|
error('ts object index: index must be a string or number', 2)
|
||||||
|
end
|
||||||
if getmetatable(t)[name] then
|
if getmetatable(t)[name] then
|
||||||
return getmetatable(t)[name]
|
return getmetatable(t)[name]
|
||||||
elseif type(name) == 'number' then
|
elseif type(name) == 'number' then
|
||||||
if not tsIsFunctionNs(rawget(t, '_tsNamespace'), 'getObject') then
|
if not tsIsFunctionNs(rawget(t, '_tsNamespace'), 'getObject') then
|
||||||
error('ts object __index: index is number, but object does not have ' ..
|
error('ts object __index: index is number, but object does not have ' ..
|
||||||
'getObject method', 2) end
|
'getObject method', 2)
|
||||||
|
end
|
||||||
return toTsObject(_bllua_ts.callobj(t._tsObjectId, 'getObject',
|
return toTsObject(_bllua_ts.callobj(t._tsObjectId, 'getObject',
|
||||||
tostring(name)))
|
tostring(name)))
|
||||||
else
|
else
|
||||||
@@ -362,17 +414,20 @@ local tsObjectMeta = {
|
|||||||
tsIsFunctionNs(rawget(t, '_tsNamespace'), name) or
|
tsIsFunctionNs(rawget(t, '_tsNamespace'), name) or
|
||||||
tsIsFunctionNs(rawget(t, '_tsName'), name)
|
tsIsFunctionNs(rawget(t, '_tsName'), name)
|
||||||
then
|
then
|
||||||
return function(t, ...)
|
return function(t2, ...)
|
||||||
local args = {...}
|
if t2 == nil or type(t2) ~= 'table' or not t2._tsObjectId then
|
||||||
local argsS = arglistToTs(args)
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
return valFromTs(
|
end
|
||||||
_bllua_ts.callobj(rawget(t,'_tsObjectId'), name, unpack(argsS)),
|
local argsS = arglistToTs({ ... })
|
||||||
rawget(t,'_tsName') and rawget(t,'_tsName')..'::'..name,
|
local res =
|
||||||
rawget(t,'_tsNamespace')..'::'..name)
|
_bllua_ts.callobj(t2._tsObjectId, name, unpack(argsS))
|
||||||
|
return valFromTs(res,
|
||||||
|
t2._tsName and t2._tsName .. '::' .. name,
|
||||||
|
t2._tsNamespace .. '::' .. name)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return valFromTs(
|
local res = _bllua_ts.getfield(rawget(t, '_tsObjectId'), name)
|
||||||
_bllua_ts.getfield(rawget(t,'_tsObjectId'), name),
|
return valFromTs(res,
|
||||||
rawget(t, '_tsName') and rawget(t, '_tsName') .. '.' .. name,
|
rawget(t, '_tsName') and rawget(t, '_tsName') .. '.' .. name,
|
||||||
rawget(t, '_tsNamespace') .. '.' .. name)
|
rawget(t, '_tsNamespace') .. '.' .. name)
|
||||||
end
|
end
|
||||||
@@ -383,9 +438,11 @@ local tsObjectMeta = {
|
|||||||
-- Use :set() to set Torque data
|
-- Use :set() to set Torque data
|
||||||
__newindex = function(t, name, val)
|
__newindex = function(t, name, val)
|
||||||
if rawget(t, '_deleted') then
|
if rawget(t, '_deleted') then
|
||||||
error('ts object newindex: object no longer exists', 2) end
|
error('ts object newindex: object no longer exists', 2)
|
||||||
|
end
|
||||||
if type(name) ~= 'string' then
|
if type(name) ~= 'string' then
|
||||||
error('ts object newindex: index must be a string', 2) end
|
error('ts object newindex: index must be a string', 2)
|
||||||
|
end
|
||||||
rawset(t, name, val)
|
rawset(t, name, val)
|
||||||
-- create strong reference since it's now storing lua data
|
-- create strong reference since it's now storing lua data
|
||||||
bl._objectsStrong[rawget(t, '_tsObjectId')] = t
|
bl._objectsStrong[rawget(t, '_tsObjectId')] = t
|
||||||
@@ -394,11 +451,14 @@ local tsObjectMeta = {
|
|||||||
-- Use to set torque data
|
-- Use to set torque data
|
||||||
set = function(t, name, val)
|
set = function(t, name, val)
|
||||||
if t == nil or type(t) ~= 'table' or not t._tsObjectId then
|
if t == nil or type(t) ~= 'table' or not t._tsObjectId then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object method: object no longer exists', 2) end
|
error('ts object method: object no longer exists', 2)
|
||||||
|
end
|
||||||
if type(name) ~= 'string' then
|
if type(name) ~= 'string' then
|
||||||
error('ts object :set(): index must be a string', 2) end
|
error('ts object :set(): index must be a string', 2)
|
||||||
|
end
|
||||||
_bllua_ts.setfield(t._tsObjectId, name, valToTs(val))
|
_bllua_ts.setfield(t._tsObjectId, name, valToTs(val))
|
||||||
end,
|
end,
|
||||||
-- __tostring: Called when printing
|
-- __tostring: Called when printing
|
||||||
@@ -412,9 +472,11 @@ local tsObjectMeta = {
|
|||||||
-- If the object has a getCount method, return its count
|
-- If the object has a getCount method, return its count
|
||||||
__len = function(t)
|
__len = function(t)
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object __len: object no longer exists', 2) end
|
error('ts object __len: object no longer exists', 2)
|
||||||
|
end
|
||||||
if not tsIsFunctionNs(t._tsNamespace, 'getCount') then
|
if not tsIsFunctionNs(t._tsNamespace, 'getCount') then
|
||||||
error('ts object __len: object has no getCount method', 2) end
|
error('ts object __len: object has no getCount method', 2)
|
||||||
|
end
|
||||||
return tonumber(_bllua_ts.callobj(t._tsObjectId, 'getCount'))
|
return tonumber(_bllua_ts.callobj(t._tsObjectId, 'getCount'))
|
||||||
end,
|
end,
|
||||||
-- object:members()
|
-- object:members()
|
||||||
@@ -422,14 +484,17 @@ local tsObjectMeta = {
|
|||||||
-- for index, object in group:members() do ... end
|
-- for index, object in group:members() do ... end
|
||||||
members = function(t)
|
members = function(t)
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object method: object no longer exists', 2) end
|
error('ts object method: object no longer exists', 2)
|
||||||
|
end
|
||||||
if not (
|
if not (
|
||||||
tsIsFunctionNs(t._tsNamespace, 'getCount') and
|
tsIsFunctionNs(t._tsNamespace, 'getCount') and
|
||||||
tsIsFunctionNs(t._tsNamespace, 'getObject')) then
|
tsIsFunctionNs(t._tsNamespace, 'getObject')) then
|
||||||
error('ts object :members() - ' ..
|
error('ts object :members() - ' ..
|
||||||
'Object does not have getCount and getObject methods', 2) end
|
'Object does not have getCount and getObject methods', 2)
|
||||||
|
end
|
||||||
local count = tonumber(_bllua_ts.callobj(t._tsObjectId, 'getCount'))
|
local count = tonumber(_bllua_ts.callobj(t._tsObjectId, 'getCount'))
|
||||||
local idx = 0
|
local idx = 0
|
||||||
return function()
|
return function()
|
||||||
@@ -437,7 +502,8 @@ local tsObjectMeta = {
|
|||||||
local obj = toTsObject(_bllua_ts.callobj(t._tsObjectId,
|
local obj = toTsObject(_bllua_ts.callobj(t._tsObjectId,
|
||||||
'getObject', tostring(idx)))
|
'getObject', tostring(idx)))
|
||||||
idx = idx + 1
|
idx = idx + 1
|
||||||
return idx-1, obj
|
--return idx-1, obj
|
||||||
|
return obj
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -446,23 +512,29 @@ local tsObjectMeta = {
|
|||||||
-- Wrap some Torque functions for performance and error checking
|
-- Wrap some Torque functions for performance and error checking
|
||||||
getName = function(t)
|
getName = function(t)
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object method: object no longer exists', 2) end
|
error('ts object method: object no longer exists', 2)
|
||||||
|
end
|
||||||
return t._tsName
|
return t._tsName
|
||||||
end,
|
end,
|
||||||
getId = function(t)
|
getId = function(t)
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object method: object no longer exists', 2) end
|
error('ts object method: object no longer exists', 2)
|
||||||
|
end
|
||||||
return tonumber(t._tsObjectId)
|
return tonumber(t._tsObjectId)
|
||||||
end,
|
end,
|
||||||
getType = function(t)
|
getType = function(t)
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
error('ts object method: object no longer exists', 2) end
|
error('ts object method: object no longer exists', 2)
|
||||||
|
end
|
||||||
return tsTypesByNum[_bllua_ts.callobj(t._tsObjectId, 'getType')]
|
return tsTypesByNum[_bllua_ts.callobj(t._tsObjectId, 'getType')]
|
||||||
end,
|
end,
|
||||||
---- Schedule method for objects
|
---- Schedule method for objects
|
||||||
@@ -484,7 +556,8 @@ local tsObjectMeta = {
|
|||||||
--end,
|
--end,
|
||||||
exists = function(t)
|
exists = function(t)
|
||||||
if t == nil then
|
if t == nil then
|
||||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
@@ -518,13 +591,15 @@ end
|
|||||||
-- Return a Torque object for the object ID string, or create one if none exists
|
-- Return a Torque object for the object ID string, or create one if none exists
|
||||||
toTsObject = function(idiS)
|
toTsObject = function(idiS)
|
||||||
if type(idiS) ~= 'string' then
|
if type(idiS) ~= 'string' then
|
||||||
error('toTsObject: input must be a string', 2) end
|
error('toTsObject: input must be a string', 2)
|
||||||
|
end
|
||||||
idiS = idiS:lower()
|
idiS = idiS:lower()
|
||||||
if bl._objectsWeak[idiS] then return bl._objectsWeak[idiS] end
|
if bl._objectsWeak[idiS] then return bl._objectsWeak[idiS] end
|
||||||
|
|
||||||
if not tsIsObject(idiS) then
|
if not tsIsObject(idiS) then
|
||||||
--error('toTsObject: object \''..idiS..'\' does not exist', 2) end
|
--error('toTsObject: object \''..idiS..'\' does not exist', 2) end
|
||||||
return nil end
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local className = _bllua_ts.callobj(idiS, 'getClassName')
|
local className = _bllua_ts.callobj(idiS, 'getClassName')
|
||||||
local obj = {
|
local obj = {
|
||||||
@@ -544,14 +619,13 @@ end
|
|||||||
local function safeNamespaceName(name)
|
local function safeNamespaceName(name)
|
||||||
return tostring(name:gsub(':', '_'))
|
return tostring(name:gsub(':', '_'))
|
||||||
end
|
end
|
||||||
local nscallArgStr = '%a,%b,%c,%d,%e,%f,%g,%h'
|
|
||||||
bl._cachedNamespaceCalls = {}
|
bl._cachedNamespaceCalls = {}
|
||||||
local function tsNamespacedCallTfname(name)
|
local function tsNamespacedCallTfname(name)
|
||||||
local tfname = bl._cachedNamespaceCalls[name]
|
local tfname = bl._cachedNamespaceCalls[name]
|
||||||
if not tfname then
|
if not tfname then
|
||||||
tfname = '_bllua_nscall_' .. safeNamespaceName(name)
|
tfname = '_bllua_nscall_' .. safeNamespaceName(name)
|
||||||
local tfcode = 'function '..tfname..'('..nscallArgStr..'){'..
|
local tfcode = 'function ' .. tfname .. '(' .. tsArgsLocal .. '){' ..
|
||||||
name..'('..nscallArgStr..');}'
|
name .. '(' .. tsArgsLocal .. ');}'
|
||||||
_bllua_ts.eval(tfcode)
|
_bllua_ts.eval(tfcode)
|
||||||
bl._cachedNamespaceCalls[name] = tfname
|
bl._cachedNamespaceCalls[name] = tfname
|
||||||
end
|
end
|
||||||
@@ -559,9 +633,9 @@ local function tsNamespacedCallTfname(name)
|
|||||||
end
|
end
|
||||||
local function tsCallGen(name)
|
local function tsCallGen(name)
|
||||||
return function(...)
|
return function(...)
|
||||||
local args = {...}
|
local argsS = arglistToTs({ ... })
|
||||||
local argsS = arglistToTs(args)
|
local res = _bllua_ts.call(name, unpack(argsS))
|
||||||
return valFromTs(_bllua_ts.call(name, unpack(argsS)), name)
|
return valFromTs(res, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -587,14 +661,16 @@ local tsMeta = {
|
|||||||
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
||||||
return tsCallGen(tsNamespacedCallTfname(name))
|
return tsCallGen(tsNamespacedCallTfname(name))
|
||||||
else
|
else
|
||||||
return valFromTs(_bllua_ts.getvar(name), name)
|
local res = _bllua_ts.getvar(name)
|
||||||
|
return valFromTs(res, name)
|
||||||
end
|
end
|
||||||
elseif tsIsFunction(name) then
|
elseif tsIsFunction(name) then
|
||||||
return tsCallGen(name)
|
return tsCallGen(name)
|
||||||
elseif tsIsObject(name) then
|
elseif tsIsObject(name) then
|
||||||
return toTsObject(name)
|
return toTsObject(name)
|
||||||
else
|
else
|
||||||
return valFromTs(_bllua_ts.getvar(name), name)
|
local res = _bllua_ts.getvar(name)
|
||||||
|
return valFromTs(res, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@@ -612,16 +688,22 @@ function bl.call(func, ...)
|
|||||||
local argsS = arglistToTs(args)
|
local argsS = arglistToTs(args)
|
||||||
return _bllua_ts.call(func, unpack(argsS))
|
return _bllua_ts.call(func, unpack(argsS))
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.eval(code)
|
function bl.eval(code)
|
||||||
return valFromTs(_bllua_ts.eval(code))
|
local res = _bllua_ts.eval(code)
|
||||||
|
return valFromTs(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.exec(file)
|
function bl.exec(file)
|
||||||
return valFromTs(_bllua_ts.call('exec', file))
|
local res = _bllua_ts.call('exec', file)
|
||||||
|
return valFromTs(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.array(name, ...)
|
function bl.array(name, ...)
|
||||||
local rest = { ... }
|
local rest = { ... }
|
||||||
return name .. table.concat(rest, '_')
|
return name .. table.concat(rest, '_')
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.boolean(val)
|
function bl.boolean(val)
|
||||||
return val ~= nil and
|
return val ~= nil and
|
||||||
val ~= false and
|
val ~= false and
|
||||||
@@ -629,6 +711,7 @@ function bl.boolean(val)
|
|||||||
--val~='0' and
|
--val~='0' and
|
||||||
val ~= 0
|
val ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.object(id)
|
function bl.object(id)
|
||||||
if type(id) == 'table' and id._tsObjectId then
|
if type(id) == 'table' and id._tsObjectId then
|
||||||
return id
|
return id
|
||||||
@@ -638,6 +721,7 @@ function bl.object(id)
|
|||||||
error('bl.object: id must be a ts object, number, or string', 2)
|
error('bl.object: id must be a ts object, number, or string', 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.string(val)
|
function bl.string(val)
|
||||||
return valFromTsTostring(val)
|
return valFromTsTostring(val)
|
||||||
end
|
end
|
||||||
@@ -645,26 +729,36 @@ end
|
|||||||
-- Lua calling from TS
|
-- Lua calling from TS
|
||||||
local luaLookup
|
local luaLookup
|
||||||
luaLookup = function(tbl, name, set, val)
|
luaLookup = function(tbl, name, set, val)
|
||||||
print('lookup', tbl, name, set, val)
|
|
||||||
if name:find('%.') then
|
if name:find('%.') then
|
||||||
local first, rest = name:match('^([^%.:]+)%.(.+)$')
|
local first, rest = name:match('^([^%.:]+)%.(.+)$')
|
||||||
if not isValidFuncName(first) then
|
if not isValidFuncName(first) then
|
||||||
error('luaLookup: invalid name \''..tostring(first)..'\'', 3) end
|
error('luaLookup: invalid name \'' .. tostring(first) .. '\'', 3)
|
||||||
if not tbl[first] then
|
end
|
||||||
if set then tbl[first] = {}
|
if tbl[first] == nil then
|
||||||
else return nil end
|
if set then
|
||||||
|
tbl[first] = {}
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return luaLookup(tbl[first], rest, set, val)
|
return luaLookup(tbl[first], rest, set, val)
|
||||||
elseif name:find(':') then
|
elseif name:find(':') then
|
||||||
local first, rest = name:match('^([^%.:]+):(.*)$')
|
local first, rest = name:match('^([^%.:]+):(.*)$')
|
||||||
if rest:find('[%.:]') then
|
if rest:find('[%.:]') then
|
||||||
error('luacall: cannot have : or . after :', 3) end
|
error('luacall: cannot have : or . after :', 3)
|
||||||
|
end
|
||||||
if not isValidFuncName(first) then
|
if not isValidFuncName(first) then
|
||||||
error('luacall: invalid name \''..tostring(first)..'\'', 3) end
|
error('luacall: invalid name \'' .. tostring(first) .. '\'', 3)
|
||||||
|
end
|
||||||
|
if not isValidFuncName(rest) then
|
||||||
|
error('luacall: invalid method name \'' .. tostring(first) .. '\'', 3)
|
||||||
|
end
|
||||||
if not tbl[first] then
|
if not tbl[first] then
|
||||||
error('luacall: no object named \''..rest..'\'', 3) end
|
error('luacall: no object named \'' .. rest .. '\'', 3)
|
||||||
if not tbl[first][rest] then
|
end
|
||||||
error('luacall: no method named \''..rest..'\'', 3) end
|
if tbl[first][rest] == nil then
|
||||||
|
error('luacall: no method named \'' .. rest .. '\'', 3)
|
||||||
|
end
|
||||||
return function(...)
|
return function(...)
|
||||||
tbl[first][rest](tbl[first], ...)
|
tbl[first][rest](tbl[first], ...)
|
||||||
end
|
end
|
||||||
@@ -681,19 +775,23 @@ function _bllua_call(fname, ...)
|
|||||||
local args = arglistFromTs(fname:lower(), { ... }) -- todo: separate lua from ts func names?
|
local args = arglistFromTs(fname:lower(), { ... }) -- todo: separate lua from ts func names?
|
||||||
local func = luaLookup(_G, fname)
|
local func = luaLookup(_G, fname)
|
||||||
if not func then
|
if not func then
|
||||||
error('luacall: no global in lua named \''..name..'\'', 2) end
|
error('luacall: no global in lua named \'' .. fname .. '\'', 2)
|
||||||
|
end
|
||||||
local res = func(unpack(args))
|
local res = func(unpack(args))
|
||||||
return valToTs(res)
|
return valToTs(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
function _bllua_getvar(vname)
|
function _bllua_getvar(vname)
|
||||||
return valToTs(luaLookup(_G, vname))
|
return valToTs(luaLookup(_G, vname))
|
||||||
end
|
end
|
||||||
|
|
||||||
function _bllua_setvar(vname, valS)
|
function _bllua_setvar(vname, valS)
|
||||||
return valToTs(luaLookup(_G, vname, true, valFromTs(valS, vname))) -- todo: separate lua from ts var names?
|
return valToTs(luaLookup(_G, vname, true, valFromTs(valS, vname))) -- todo: separate lua from ts var names?
|
||||||
end
|
end
|
||||||
function _bllua_eval(code) return loadstring(code)() end
|
|
||||||
function _bllua_exec(fn) return dofile(fn, 2) end
|
|
||||||
|
|
||||||
|
function _bllua_eval(code) return loadstring(code)() end
|
||||||
|
|
||||||
|
function _bllua_exec(fn) return dofile(fn, 2) end
|
||||||
|
|
||||||
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
||||||
-- bl.schedule(time, function, args...)
|
-- bl.schedule(time, function, args...)
|
||||||
@@ -721,6 +819,7 @@ function bl.schedule(time, cb, ...)
|
|||||||
bl._scheduleTable[id] = sch
|
bl._scheduleTable[id] = sch
|
||||||
return sch
|
return sch
|
||||||
end
|
end
|
||||||
|
|
||||||
function _bllua_schedule_callback(idS)
|
function _bllua_schedule_callback(idS)
|
||||||
local id = tonumber(idS) or
|
local id = tonumber(idS) or
|
||||||
error('_bllua_schedule_callback: invalid id: ' .. tostring(idS))
|
error('_bllua_schedule_callback: invalid id: ' .. tostring(idS))
|
||||||
@@ -739,19 +838,21 @@ function _bllua_process_cmd(cmdS, ...)
|
|||||||
if not func then error('_bllua_process_cmd: no cmd named \'' .. cmd .. '\'') end
|
if not func then error('_bllua_process_cmd: no cmd named \'' .. cmd .. '\'') end
|
||||||
func(unpack(args)) --pcall(func, unpack(args))
|
func(unpack(args)) --pcall(func, unpack(args))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function addCmd(cmd, func)
|
local function addCmd(cmd, func)
|
||||||
if not isValidFuncName(cmd) then
|
if not isValidFuncName(cmd) then
|
||||||
error('addCmd: invalid function name \''..tostring(cmd)..'\'') end
|
error('addCmd: invalid function name \'' .. tostring(cmd) .. '\'')
|
||||||
|
end
|
||||||
bl._cmds[cmd] = func
|
bl._cmds[cmd] = func
|
||||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p'
|
_bllua_ts.eval('function ' .. cmd .. '(' .. tsArgsLocal .. '){' ..
|
||||||
_bllua_ts.eval('function '..cmd..'('..arglist..'){'..
|
'_bllua_luacall(_bllua_process_cmd,"' .. cmd .. '",' .. tsArgsLocal .. ');}')
|
||||||
'_bllua_luacall(_bllua_process_cmd,"'..cmd..'",'..arglist..');}')
|
|
||||||
end
|
end
|
||||||
function bl.addServerCmd(name, func)
|
function bl.addServerCmd(name, func)
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
addCmd('servercmd' .. name, func)
|
addCmd('servercmd' .. name, func)
|
||||||
bl._forceType['servercmd' .. name .. ':1'] = 'object'
|
bl._forceType['servercmd' .. name .. ':1'] = 'object'
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.addClientCmd(name, func)
|
function bl.addClientCmd(name, func)
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
addCmd('clientcmd' .. name, func)
|
addCmd('clientcmd' .. name, func)
|
||||||
@@ -763,11 +864,14 @@ function bl.commandToServer(cmd, ...)
|
|||||||
_bllua_ts.call('addTaggedString', cmd),
|
_bllua_ts.call('addTaggedString', cmd),
|
||||||
unpack(arglistToTs({ ... })))
|
unpack(arglistToTs({ ... })))
|
||||||
end
|
end
|
||||||
function bl.commandToClient(cmd, ...)
|
|
||||||
|
function bl.commandToClient(client, cmd, ...)
|
||||||
_bllua_ts.call('commandToClient',
|
_bllua_ts.call('commandToClient',
|
||||||
|
valToTs(client),
|
||||||
_bllua_ts.call('addTaggedString', cmd),
|
_bllua_ts.call('addTaggedString', cmd),
|
||||||
unpack(arglistToTs({ ... })))
|
unpack(arglistToTs({ ... })))
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.commandToAll(cmd, ...)
|
function bl.commandToAll(cmd, ...)
|
||||||
_bllua_ts.call('commandToAll',
|
_bllua_ts.call('commandToAll',
|
||||||
_bllua_ts.call('addTaggedString', cmd),
|
_bllua_ts.call('addTaggedString', cmd),
|
||||||
@@ -793,26 +897,25 @@ local function deactivatePackage(pkg)
|
|||||||
_bllua_ts.call('deactivatePackage', pkg)
|
_bllua_ts.call('deactivatePackage', pkg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local hookNargs = 8
|
|
||||||
local hookArglistLocal = '%a,%b,%c,%d,%e,%f,%g,%h'
|
|
||||||
local hookArglistGlobal = '$_bllua_hook_arg1,$_bllua_hook_arg2,$_bllua_hook_arg3,$_bllua_hook_arg4,$_bllua_hook_arg5,$_bllua_hook_arg6,$_bllua_hook_arg7,$_bllua_hook_arg8'
|
|
||||||
bl._hooks = bl._hooks or {}
|
bl._hooks = bl._hooks or {}
|
||||||
function _bllua_process_hook_before(pkgS, nameS, ...)
|
function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||||
local args = arglistFromTs(nameS, { ... })
|
local args = arglistFromTs(nameS, { ... })
|
||||||
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
||||||
bl._hooks[pkgS][nameS].before
|
bl._hooks[pkgS][nameS].before
|
||||||
if not func then
|
if not func then
|
||||||
error('_bllua_process_hook_before: no hook for '..pkgs..':'..nameS) end
|
error('_bllua_process_hook_before: no hook for ' .. pkgs .. ':' .. nameS)
|
||||||
|
end
|
||||||
_bllua_ts.setvar('_bllua_hook_abort', '0')
|
_bllua_ts.setvar('_bllua_hook_abort', '0')
|
||||||
func(args) --pcall(func, args)
|
func(args) --pcall(func, args)
|
||||||
if args._return then
|
if args._return then
|
||||||
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
||||||
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
||||||
end
|
end
|
||||||
for i=1,hookNargs do
|
for i = 1, tsMaxArgs do
|
||||||
_bllua_ts.setvar('_bllua_hook_arg' .. i, valToTs(args[i]))
|
_bllua_ts.setvar('_bllua_hook_arg' .. i, valToTs(args[i]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _bllua_process_hook_after(pkgS, nameS, resultS, ...)
|
function _bllua_process_hook_after(pkgS, nameS, resultS, ...)
|
||||||
nameS = nameS:lower()
|
nameS = nameS:lower()
|
||||||
local args = arglistFromTs(nameS, { ... })
|
local args = arglistFromTs(nameS, { ... })
|
||||||
@@ -820,15 +923,17 @@ function _bllua_process_hook_after(pkgS, nameS, resultS, ...)
|
|||||||
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
||||||
bl._hooks[pkgS][nameS].after
|
bl._hooks[pkgS][nameS].after
|
||||||
if not func then
|
if not func then
|
||||||
error('_bllua_process_hook_after: no hook for '..pkgs..':'..nameS) end
|
error('_bllua_process_hook_after: no hook for ' .. pkgs .. ':' .. nameS)
|
||||||
|
end
|
||||||
func(args) --pcall(func, args)
|
func(args) --pcall(func, args)
|
||||||
return valToTs(args._return)
|
return valToTs(args._return)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function updateHook(pkg, name, hk)
|
local function updateHook(pkg, name, hk)
|
||||||
local beforeCode = hk.before and
|
local beforeCode = hk.before and
|
||||||
('_bllua_luacall("_bllua_process_hook_before","' .. pkg .. '","' .. name ..
|
('_bllua_luacall("_bllua_process_hook_before","' .. pkg .. '","' .. name ..
|
||||||
'",'..hookArglistLocal..');') or ''
|
'",' .. tsArgsLocal .. ');') or ''
|
||||||
local arglist = (hk.before and hookArglistGlobal or hookArglistLocal)
|
local arglist = (hk.before and tsArgsGlobal or tsArgsLocal)
|
||||||
local parentCode =
|
local parentCode =
|
||||||
tsIsFunctionNsname(name) and -- only call parent if it exists
|
tsIsFunctionNsname(name) and -- only call parent if it exists
|
||||||
(hk.before and
|
(hk.before and
|
||||||
@@ -841,21 +946,26 @@ local function updateHook(pkg, name, hk)
|
|||||||
arglist .. ');') or ''
|
arglist .. ');') or ''
|
||||||
local code =
|
local code =
|
||||||
'package ' .. pkg .. '{' ..
|
'package ' .. pkg .. '{' ..
|
||||||
'function '..name..'('..hookArglistLocal..'){'..
|
'function ' .. name .. '(' .. tsArgsLocal .. '){' ..
|
||||||
beforeCode .. parentCode .. afterCode ..
|
beforeCode .. parentCode .. afterCode ..
|
||||||
'}' ..
|
'}' ..
|
||||||
'};'
|
'};'
|
||||||
|
print('bl.hook eval output: [[' .. code .. ']]')
|
||||||
_bllua_ts.eval(code)
|
_bllua_ts.eval(code)
|
||||||
end
|
end
|
||||||
function bl.hook(pkg, name, time, func)
|
function bl.hook(pkg, name, time, func)
|
||||||
if not isValidFuncName(pkg) then
|
if not isValidFuncName(pkg) then
|
||||||
error('bl.hook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
error('bl.hook: argument #1: invalid package name \'' .. tostring(pkg) .. '\'', 2)
|
||||||
|
end
|
||||||
if not isValidFuncNameNs(name) then
|
if not isValidFuncNameNs(name) then
|
||||||
error('bl.hook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
error('bl.hook: argument #2: invalid function name \'' .. tostring(name) .. '\'', 2)
|
||||||
|
end
|
||||||
if time ~= 'before' and time ~= 'after' then
|
if time ~= 'before' and time ~= 'after' then
|
||||||
error('bl.hook: argument #3: time must be \'before\' or \'after\'', 2) end
|
error('bl.hook: argument #3: time must be \'before\' or \'after\'', 2)
|
||||||
|
end
|
||||||
if type(func) ~= 'function' then
|
if type(func) ~= 'function' then
|
||||||
error('bl.hook: argument #4: expected a function', 2) end
|
error('bl.hook: argument #4: expected a function', 2)
|
||||||
|
end
|
||||||
|
|
||||||
bl._hooks[pkg] = bl._hooks[pkg] or {}
|
bl._hooks[pkg] = bl._hooks[pkg] or {}
|
||||||
bl._hooks[pkg][name] = bl._hooks[pkg][name] or {}
|
bl._hooks[pkg][name] = bl._hooks[pkg][name] or {}
|
||||||
@@ -864,16 +974,20 @@ function bl.hook(pkg, name, time, func)
|
|||||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||||
activatePackage(pkg)
|
activatePackage(pkg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function tableEmpty(t)
|
local function tableEmpty(t)
|
||||||
return next(t) ~= nil
|
return next(t) ~= nil
|
||||||
end
|
end
|
||||||
function bl.unhook(pkg, name, time)
|
function bl.unhook(pkg, name, time)
|
||||||
if not isValidFuncName(pkg) then
|
if not isValidFuncName(pkg) then
|
||||||
error('bl.unhook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
error('bl.unhook: argument #1: invalid package name \'' .. tostring(pkg) .. '\'', 2)
|
||||||
if not isValidFuncNameNs(name) then
|
end
|
||||||
error('bl.unhook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
if name and not isValidFuncNameNs(name) then
|
||||||
if time~='before' and time~='after' then
|
error('bl.unhook: argument #2: invalid function name \'' .. tostring(name) .. '\'', 2)
|
||||||
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2) end
|
end
|
||||||
|
if time and time ~= 'before' and time ~= 'after' then
|
||||||
|
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2)
|
||||||
|
end
|
||||||
|
|
||||||
if not name then
|
if not name then
|
||||||
if bl._hooks[pkg] then
|
if bl._hooks[pkg] then
|
||||||
@@ -897,12 +1011,16 @@ function bl.unhook(pkg, name, time)
|
|||||||
updateHook(pkg, name, {})
|
updateHook(pkg, name, {})
|
||||||
else
|
else
|
||||||
if time ~= 'before' and time ~= 'after' then
|
if time ~= 'before' and time ~= 'after' then
|
||||||
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2) end
|
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2)
|
||||||
|
end
|
||||||
bl._hooks[pkg][name][time] = nil
|
bl._hooks[pkg][name][time] = nil
|
||||||
if tableEmpty(bl._hooks[pkg][name]) and tableEmpty(bl._hooks[pkg]) then
|
if tableEmpty(bl._hooks[pkg][name]) then
|
||||||
|
bl._hooks[pkg][name] = nil
|
||||||
|
end
|
||||||
|
if tableEmpty(bl._hooks[pkg]) then
|
||||||
bl._hooks[pkg] = nil
|
bl._hooks[pkg] = nil
|
||||||
deactivatePackage(pkg)
|
|
||||||
updateHook(pkg, name, {})
|
updateHook(pkg, name, {})
|
||||||
|
deactivatePackage(pkg)
|
||||||
else
|
else
|
||||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||||
end
|
end
|
||||||
@@ -917,14 +1035,16 @@ end
|
|||||||
-- Container search/raycast
|
-- Container search/raycast
|
||||||
local function vecToTs(v)
|
local function vecToTs(v)
|
||||||
if not isTsVector(v) then
|
if not isTsVector(v) then
|
||||||
error('vecToTs: argument is not a vector', 3) end
|
error('vecToTs: argument is not a vector', 3)
|
||||||
|
end
|
||||||
return table.concat(v, ' ')
|
return table.concat(v, ' ')
|
||||||
end
|
end
|
||||||
local function maskToTs(mask)
|
local function maskToTs(mask)
|
||||||
if type(mask) == 'string' then
|
if type(mask) == 'string' then
|
||||||
local val = tsTypesByName[mask:lower()]
|
local val = tsTypesByName[mask:lower()]
|
||||||
if not val then
|
if not val then
|
||||||
error('maskToTs: invalid mask \''..mask..'\'', 3) end
|
error('maskToTs: invalid mask \'' .. mask .. '\'', 3)
|
||||||
|
end
|
||||||
return tostring(val)
|
return tostring(val)
|
||||||
elseif type(mask) == 'table' then
|
elseif type(mask) == 'table' then
|
||||||
local tval = 0
|
local tval = 0
|
||||||
@@ -934,7 +1054,8 @@ local function maskToTs(mask)
|
|||||||
local val = tsTypesByName[v:lower()]
|
local val = tsTypesByName[v:lower()]
|
||||||
if not val then
|
if not val then
|
||||||
error('maskToTs: invalid mask \'' .. v ..
|
error('maskToTs: invalid mask \'' .. v ..
|
||||||
'\' at index '..i..' in mask list', 3) end
|
'\' at index ' .. i .. ' in mask list', 3)
|
||||||
|
end
|
||||||
tval = tval + val
|
tval = tval + val
|
||||||
seen[v] = true
|
seen[v] = true
|
||||||
end
|
end
|
||||||
@@ -958,7 +1079,7 @@ function bl.raycast(start, stop, mask, ignores)
|
|||||||
local stopS = vecToTs(start)
|
local stopS = vecToTs(start)
|
||||||
local maskS = maskToTs(mask)
|
local maskS = maskToTs(mask)
|
||||||
local ignoresS = {}
|
local ignoresS = {}
|
||||||
for _,v in ipairs(ignores) do
|
for _, v in ipairsNilable(ignores) do
|
||||||
table.insert(ignoresS, objToTs(v))
|
table.insert(ignoresS, objToTs(v))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -976,6 +1097,7 @@ function bl.raycast(start, stop, mask, ignores)
|
|||||||
return hit, pos, norm
|
return hit, pos, norm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function tsContainerSearchIterator()
|
local function tsContainerSearchIterator()
|
||||||
local retS = _bllua_ts.call('containerSearchNext')
|
local retS = _bllua_ts.call('containerSearchNext')
|
||||||
if retS == '0' then
|
if retS == '0' then
|
||||||
@@ -992,10 +1114,12 @@ function bl.boxSearch(pos, size, mask)
|
|||||||
_bllua_ts.call('initContainerBoxSearch', posS, sizeS, maskS)
|
_bllua_ts.call('initContainerBoxSearch', posS, sizeS, maskS)
|
||||||
return tsContainerSearchIterator
|
return tsContainerSearchIterator
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.radiusSearch(pos, radius, mask)
|
function bl.radiusSearch(pos, radius, mask)
|
||||||
local posS = vecToTs(pos)
|
local posS = vecToTs(pos)
|
||||||
if type(radius) ~= 'number' then
|
if type(radius) ~= 'number' then
|
||||||
error('bl.radiusSearch: argument #2: radius must be a number', 2) end
|
error('bl.radiusSearch: argument #2: radius must be a number', 2)
|
||||||
|
end
|
||||||
local radiusS = tostring(radius)
|
local radiusS = tostring(radius)
|
||||||
local maskS = maskToTs(mask)
|
local maskS = maskToTs(mask)
|
||||||
|
|
||||||
@@ -1007,7 +1131,7 @@ end
|
|||||||
local maxTsArgLen = 8192
|
local maxTsArgLen = 8192
|
||||||
local function valsToString(vals)
|
local function valsToString(vals)
|
||||||
local strs = {}
|
local strs = {}
|
||||||
for i,v in ipairs(vals) do
|
for i, v in ipairsNilable(vals) do
|
||||||
local tstr = table.tostring(v)
|
local tstr = table.tostring(v)
|
||||||
if #tstr > maxTsArgLen then
|
if #tstr > maxTsArgLen then
|
||||||
tstr = tostring(v)
|
tstr = tostring(v)
|
||||||
@@ -1033,7 +1157,8 @@ local function createTsObj(keyword, class, name, inherit, props)
|
|||||||
if props then
|
if props then
|
||||||
for k, v in pairs(props) do
|
for k, v in pairs(props) do
|
||||||
if not isValidFuncName(k) then
|
if not isValidFuncName(k) then
|
||||||
error('bl.new/bl.datablock: invalid property name \''..k..'\'') end
|
error('bl.new/bl.datablock: invalid property name \'' .. k .. '\'')
|
||||||
|
end
|
||||||
table.insert(propsT, k .. '="' .. valToTs(v) .. '";')
|
table.insert(propsT, k .. '="' .. valToTs(v) .. '";')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1044,7 +1169,8 @@ local function createTsObj(keyword, class, name, inherit, props)
|
|||||||
table.concat(propsT) .. '};')
|
table.concat(propsT) .. '};')
|
||||||
local obj = toTsObject(objS)
|
local obj = toTsObject(objS)
|
||||||
if not obj then
|
if not obj then
|
||||||
error('bl.new/bl.datablock: failed to create object', 3) end
|
error('bl.new/bl.datablock: failed to create object', 3)
|
||||||
|
end
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
@@ -1069,13 +1195,15 @@ local function parseTsDecl(decl)
|
|||||||
(inherit == nil or isValidFuncName(inherit))) then
|
(inherit == nil or isValidFuncName(inherit))) then
|
||||||
error('bl.new/bl.datablock: invalid decl \'' .. decl .. '\'\n' ..
|
error('bl.new/bl.datablock: invalid decl \'' .. decl .. '\'\n' ..
|
||||||
'must be of the format: \'className\', \'className name\', ' ..
|
'must be of the format: \'className\', \'className name\', ' ..
|
||||||
'\'className :inherit\', or \'className name:inherit\'', 3) end
|
'\'className :inherit\', or \'className name:inherit\'', 3)
|
||||||
|
end
|
||||||
return class, name, inherit
|
return class, name, inherit
|
||||||
end
|
end
|
||||||
function bl.new(decl, props)
|
function bl.new(decl, props)
|
||||||
local class, name, inherit = parseTsDecl(decl)
|
local class, name, inherit = parseTsDecl(decl)
|
||||||
return createTsObj('new', class, name, inherit, props)
|
return createTsObj('new', class, name, inherit, props)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.datablock(decl, props)
|
function bl.datablock(decl, props)
|
||||||
local class, name, inherit = parseTsDecl(decl)
|
local class, name, inherit = parseTsDecl(decl)
|
||||||
if not name then error('bl.datablock: must specify a name', 2) end
|
if not name then error('bl.datablock: must specify a name', 2) end
|
||||||
|
|||||||
@@ -93,11 +93,15 @@ local allowed_zip_dirs = tflip {
|
|||||||
local function io_open_absolute(fn, mode)
|
local function io_open_absolute(fn, mode)
|
||||||
-- if file exists, use original mode
|
-- if file exists, use original mode
|
||||||
local res, err = _bllua_io_open(fn, mode)
|
local res, err = _bllua_io_open(fn, mode)
|
||||||
if res then return res end
|
if res then
|
||||||
|
return res
|
||||||
|
elseif err and not err:find('No such file or directory$') then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
-- otherwise, if TS sees file but Lua doesn't, it must be in a zip, so use TS reader
|
-- otherwise, if TS sees file but Lua doesn't, it must be in a zip, so use TS reader
|
||||||
local dir = fn:match('^[^/]+')
|
local dir = fn:match('^[^/]+')
|
||||||
if not allowed_zip_dirs[dir:lower()] then return nil, 'File is not in one of the allowed directories' end
|
if not allowed_zip_dirs[dir:lower()] then return nil, 'Zip is not in one of the allowed directories' end
|
||||||
local exist = _bllua_ts.call('isFile', fn) == '1'
|
local exist = _bllua_ts.call('isFile', fn) == '1'
|
||||||
if not exist then return nil, err end
|
if not exist then return nil, err end
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,19 @@ function table.map(f, ...)
|
|||||||
local u = {}
|
local u = {}
|
||||||
for k, _ in pairs(ts[1]) do
|
for k, _ in pairs(ts[1]) do
|
||||||
local args = {}
|
local args = {}
|
||||||
for j = 1, #ts do args[j] = ts[j][i] end
|
for j = 1, #ts do args[j] = ts[j][k] end
|
||||||
u[i] = f(unpack(args))
|
u[k] = f(unpack(args))
|
||||||
|
end
|
||||||
|
return u
|
||||||
|
end
|
||||||
|
|
||||||
|
function table.mapk(f, ...)
|
||||||
|
local ts = { ... }
|
||||||
|
local u = {}
|
||||||
|
for k, _ in pairs(ts[1]) do
|
||||||
|
local args = {}
|
||||||
|
for j = 1, #ts do args[j] = ts[j][k] end
|
||||||
|
u[k] = f(k, unpack(args))
|
||||||
end
|
end
|
||||||
return u
|
return u
|
||||||
end
|
end
|
||||||
@@ -30,6 +41,17 @@ function table.map_list(f, ...)
|
|||||||
return u
|
return u
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.mapi_list(f, ...)
|
||||||
|
local ts = { ... }
|
||||||
|
local u = {}
|
||||||
|
for i = 1, #ts[1] do
|
||||||
|
local args = {}
|
||||||
|
for j = 1, #ts do args[j] = ts[j][i] end
|
||||||
|
u[i] = f(i, unpack(args))
|
||||||
|
end
|
||||||
|
return u
|
||||||
|
end
|
||||||
|
|
||||||
-- Swap keys/values
|
-- Swap keys/values
|
||||||
function table.swap(t)
|
function table.swap(t)
|
||||||
local u = {}
|
local u = {}
|
||||||
@@ -193,7 +215,7 @@ valueToString = function(v, tabLevel, seen)
|
|||||||
return tostring(v)
|
return tostring(v)
|
||||||
else
|
else
|
||||||
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
||||||
return 'nil --[[ cannot serialize ' .. tostring(v) .. ' ]]'
|
return 'nil --[[ ' .. tostring(v) .. ' ]]'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function table.tostring(t)
|
function table.tostring(t)
|
||||||
|
|||||||
Reference in New Issue
Block a user