forked from redo/BlockLua
Merge branch 'master'
This commit is contained in:
@@ -6,15 +6,30 @@ local _bllua_ts = ts
|
||||
|
||||
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
|
||||
-- Apply a function to each element in a list, building a new list from the returns
|
||||
local function map(t,f)
|
||||
local u = {}
|
||||
for i,v in ipairs(t) do
|
||||
u[i] = f(v)
|
||||
local function ipairsNilable(t)
|
||||
local maxk = 0
|
||||
for k,_ in pairs(t) do
|
||||
if k>maxk then maxk = k end
|
||||
end
|
||||
local i = 0
|
||||
return function()
|
||||
i = i+1
|
||||
if i>maxk then return nil
|
||||
else return i, t[i] end
|
||||
end
|
||||
return u
|
||||
end
|
||||
|
||||
-- Validation
|
||||
local function isValidFuncName(name)
|
||||
return type(name)=='string' and name:find('^[a-zA-Z_][a-zA-Z0-9_]*$')
|
||||
end
|
||||
@@ -107,13 +122,14 @@ end
|
||||
|
||||
-- Type conversion from TS to Lua
|
||||
local fromTsForceTypes = {
|
||||
['boolean'] = tsBool,
|
||||
['object'] = function(val) toTsObject(val) end, -- wrap because toTsObject not defined yet
|
||||
['boolean'] = function(val) return tsBool(val) end,
|
||||
['object'] = function(val) return toTsObject(val) end, -- wrap because toTsObject not defined yet
|
||||
['string'] = function(val) return val end,
|
||||
}
|
||||
local function forceValFromTs(val, typ)
|
||||
return fromTsForceTypes[typ](val) or
|
||||
error('valFromTs: invalid force type '..typ, 4)
|
||||
local func = fromTsForceTypes[typ]
|
||||
if not func then error('valFromTs: invalid force type \''..typ..'\'', 4) end
|
||||
return func(val)
|
||||
end
|
||||
local function vectorFromTs(val)
|
||||
local xS,yS,zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
||||
@@ -154,7 +170,8 @@ local function multinumericFromTs(val)
|
||||
end
|
||||
end
|
||||
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
|
||||
error('valFromTs: expected string, got '..type(val), 3) end
|
||||
if name then
|
||||
@@ -177,18 +194,26 @@ local function valFromTs(val, name, name2) -- todo: ensure name and name2 are al
|
||||
-- vector, box, or axis->matrix
|
||||
local vec = multinumericFromTs(val)
|
||||
if vec then return vec end
|
||||
-- net string
|
||||
if val:sub(1,1)=='\x01' then
|
||||
return _bllua_ts.call('getTaggedString', val)
|
||||
end
|
||||
-- string
|
||||
return val
|
||||
end
|
||||
local function arglistFromTs(name, argsS)
|
||||
local args = {}
|
||||
for i,arg in ipairs(argsS) do
|
||||
for i,arg in ipairsNilable(argsS) do
|
||||
args[i] = valFromTs(arg, name..':'..i)
|
||||
end
|
||||
return args
|
||||
end
|
||||
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
|
||||
local function classFromForceTypeStr(name)
|
||||
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||
@@ -362,17 +387,19 @@ local tsObjectMeta = {
|
||||
tsIsFunctionNs(rawget(t,'_tsNamespace'), name) or
|
||||
tsIsFunctionNs(rawget(t,'_tsName'), name)
|
||||
then
|
||||
return function(t, ...)
|
||||
local args = {...}
|
||||
local argsS = arglistToTs(args)
|
||||
return valFromTs(
|
||||
_bllua_ts.callobj(rawget(t,'_tsObjectId'), name, unpack(argsS)),
|
||||
rawget(t,'_tsName') and rawget(t,'_tsName')..'::'..name,
|
||||
rawget(t,'_tsNamespace')..'::'..name)
|
||||
return function(t2, ...)
|
||||
if t2==nil or type(t2)~='table' or not t2._tsObjectId then
|
||||
error('ts object method: be sure to use :func() not .func()', 2) end
|
||||
local argsS = arglistToTs({...})
|
||||
local res =
|
||||
_bllua_ts.callobj(t2._tsObjectId, name, unpack(argsS))
|
||||
return valFromTs(res,
|
||||
t2._tsName and t2._tsName..'::'..name,
|
||||
t2._tsNamespace..'::'..name)
|
||||
end
|
||||
else
|
||||
return valFromTs(
|
||||
_bllua_ts.getfield(rawget(t,'_tsObjectId'), name),
|
||||
local res = _bllua_ts.getfield(rawget(t,'_tsObjectId'), name)
|
||||
return valFromTs(res,
|
||||
rawget(t,'_tsName') and rawget(t,'_tsName')..'.'..name,
|
||||
rawget(t,'_tsNamespace')..'.'..name)
|
||||
end
|
||||
@@ -437,7 +464,8 @@ local tsObjectMeta = {
|
||||
local obj = toTsObject(_bllua_ts.callobj(t._tsObjectId,
|
||||
'getObject', tostring(idx)))
|
||||
idx = idx+1
|
||||
return idx-1, obj
|
||||
--return idx-1, obj
|
||||
return obj
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@@ -544,14 +572,13 @@ end
|
||||
local function safeNamespaceName(name)
|
||||
return tostring(name:gsub(':', '_'))
|
||||
end
|
||||
local nscallArgStr = '%a,%b,%c,%d,%e,%f,%g,%h'
|
||||
bl._cachedNamespaceCalls = {}
|
||||
local function tsNamespacedCallTfname(name)
|
||||
local tfname = bl._cachedNamespaceCalls[name]
|
||||
if not tfname then
|
||||
tfname = '_bllua_nscall_'..safeNamespaceName(name)
|
||||
local tfcode = 'function '..tfname..'('..nscallArgStr..'){'..
|
||||
name..'('..nscallArgStr..');}'
|
||||
local tfcode = 'function '..tfname..'('..tsArgsLocal..'){'..
|
||||
name..'('..tsArgsLocal..');}'
|
||||
_bllua_ts.eval(tfcode)
|
||||
bl._cachedNamespaceCalls[name] = tfname
|
||||
end
|
||||
@@ -559,9 +586,9 @@ local function tsNamespacedCallTfname(name)
|
||||
end
|
||||
local function tsCallGen(name)
|
||||
return function(...)
|
||||
local args = {...}
|
||||
local argsS = arglistToTs(args)
|
||||
return valFromTs(_bllua_ts.call(name, unpack(argsS)), name)
|
||||
local argsS = arglistToTs({...})
|
||||
local res = _bllua_ts.call(name, unpack(argsS))
|
||||
return valFromTs(res, name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -587,14 +614,16 @@ local tsMeta = {
|
||||
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
||||
return tsCallGen(tsNamespacedCallTfname(name))
|
||||
else
|
||||
return valFromTs(_bllua_ts.getvar(name), name)
|
||||
local res = _bllua_ts.getvar(name)
|
||||
return valFromTs(res, name)
|
||||
end
|
||||
elseif tsIsFunction(name) then
|
||||
return tsCallGen(name)
|
||||
elseif tsIsObject(name) then
|
||||
return toTsObject(name)
|
||||
else
|
||||
return valFromTs(_bllua_ts.getvar(name), name)
|
||||
local res = _bllua_ts.getvar(name)
|
||||
return valFromTs(res, name)
|
||||
end
|
||||
end
|
||||
end,
|
||||
@@ -613,10 +642,12 @@ function bl.call(func, ...)
|
||||
return _bllua_ts.call(func, unpack(argsS))
|
||||
end
|
||||
function bl.eval(code)
|
||||
return valFromTs(_bllua_ts.eval(code))
|
||||
local res = _bllua_ts.eval(code)
|
||||
return valFromTs(res)
|
||||
end
|
||||
function bl.exec(file)
|
||||
return valFromTs(_bllua_ts.call('exec', file))
|
||||
local res = _bllua_ts.call('exec', file)
|
||||
return valFromTs(res)
|
||||
end
|
||||
function bl.array(name, ...)
|
||||
local rest = {...}
|
||||
@@ -645,12 +676,11 @@ end
|
||||
-- Lua calling from TS
|
||||
local luaLookup
|
||||
luaLookup = function(tbl, name, set, val)
|
||||
print('lookup', tbl, name, set, val)
|
||||
if name:find('%.') then
|
||||
local first, rest = name:match('^([^%.:]+)%.(.+)$')
|
||||
if not isValidFuncName(first) then
|
||||
error('luaLookup: invalid name \''..tostring(first)..'\'', 3) end
|
||||
if not tbl[first] then
|
||||
if tbl[first]==nil then
|
||||
if set then tbl[first] = {}
|
||||
else return nil end
|
||||
end
|
||||
@@ -661,9 +691,11 @@ luaLookup = function(tbl, name, set, val)
|
||||
error('luacall: cannot have : or . after :', 3) end
|
||||
if not isValidFuncName(first) then
|
||||
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
|
||||
error('luacall: no object named \''..rest..'\'', 3) end
|
||||
if not tbl[first][rest] then
|
||||
if tbl[first][rest]==nil then
|
||||
error('luacall: no method named \''..rest..'\'', 3) end
|
||||
return function(...)
|
||||
tbl[first][rest](tbl[first], ...)
|
||||
@@ -681,7 +713,7 @@ function _bllua_call(fname, ...)
|
||||
local args = arglistFromTs(fname:lower(), {...}) -- todo: separate lua from ts func names?
|
||||
local func = luaLookup(_G, fname)
|
||||
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))
|
||||
return valToTs(res)
|
||||
end
|
||||
@@ -743,9 +775,8 @@ local function addCmd(cmd, func)
|
||||
if not isValidFuncName(cmd) then
|
||||
error('addCmd: invalid function name \''..tostring(cmd)..'\'') end
|
||||
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..'('..arglist..'){'..
|
||||
'_bllua_luacall(_bllua_process_cmd,"'..cmd..'",'..arglist..');}')
|
||||
_bllua_ts.eval('function '..cmd..'('..tsArgsLocal..'){'..
|
||||
'_bllua_luacall(_bllua_process_cmd,"'..cmd..'",'..tsArgsLocal..');}')
|
||||
end
|
||||
function bl.addServerCmd(name, func)
|
||||
name = name:lower()
|
||||
@@ -763,8 +794,9 @@ function bl.commandToServer(cmd, ...)
|
||||
_bllua_ts.call('addTaggedString', cmd),
|
||||
unpack(arglistToTs({...})))
|
||||
end
|
||||
function bl.commandToClient(cmd, ...)
|
||||
function bl.commandToClient(client, cmd, ...)
|
||||
_bllua_ts.call('commandToClient',
|
||||
valToTs(client),
|
||||
_bllua_ts.call('addTaggedString', cmd),
|
||||
unpack(arglistToTs({...})))
|
||||
end
|
||||
@@ -793,9 +825,6 @@ local function deactivatePackage(pkg)
|
||||
_bllua_ts.call('deactivatePackage', pkg)
|
||||
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 {}
|
||||
function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||
local args = arglistFromTs(nameS, {...})
|
||||
@@ -809,7 +838,7 @@ function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
||||
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
||||
end
|
||||
for i=1,hookNargs do
|
||||
for i=1,tsMaxArgs do
|
||||
_bllua_ts.setvar('_bllua_hook_arg'..i, valToTs(args[i]))
|
||||
end
|
||||
end
|
||||
@@ -826,13 +855,13 @@ function _bllua_process_hook_after(pkgS, nameS, resultS, ...)
|
||||
end
|
||||
local function updateHook(pkg, name, hk)
|
||||
local beforeCode = hk.before and
|
||||
('_bllua_luacall("_bllua_process_hook_before", "'..pkg..'","'..name..
|
||||
'",'..hookArglistLocal..');') or ''
|
||||
local arglist = (hk.before and hookArglistGlobal or hookArglistLocal)
|
||||
('_bllua_luacall("_bllua_process_hook_before","'..pkg..'","'..name..
|
||||
'",'..tsArgsLocal..');') or ''
|
||||
local arglist = (hk.before and tsArgsGlobal or tsArgsLocal)
|
||||
local parentCode =
|
||||
tsIsFunctionNsname(name) and -- only call parent if it exists
|
||||
(hk.before and
|
||||
'if($_bllua_hook_abort)return $_bllua_hook_return; else ' or '')..
|
||||
'if($_bllua_hook_abort)return $_bllua_hook_return;else ' or '')..
|
||||
((hk.after and '%result=' or 'return ')..
|
||||
'parent::'..name:match('[^:]+$')..
|
||||
'('..arglist..');') or ''
|
||||
@@ -841,10 +870,11 @@ local function updateHook(pkg, name, hk)
|
||||
arglist..');') or ''
|
||||
local code =
|
||||
'package '..pkg..'{'..
|
||||
'function '..name..'('..hookArglistLocal..'){'..
|
||||
'function '..name..'('..tsArgsLocal..'){'..
|
||||
beforeCode..parentCode..afterCode..
|
||||
'}'..
|
||||
'};'
|
||||
print('bl.hook eval output: [['..code..']]')
|
||||
_bllua_ts.eval(code)
|
||||
end
|
||||
function bl.hook(pkg, name, time, func)
|
||||
@@ -870,9 +900,9 @@ end
|
||||
function bl.unhook(pkg, name, time)
|
||||
if not isValidFuncName(pkg) then
|
||||
error('bl.unhook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
||||
if not isValidFuncNameNs(name) then
|
||||
if name and not isValidFuncNameNs(name) then
|
||||
error('bl.unhook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
||||
if time~='before' and time~='after' then
|
||||
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
|
||||
@@ -899,10 +929,13 @@ 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 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
|
||||
deactivatePackage(pkg)
|
||||
updateHook(pkg, name, {})
|
||||
deactivatePackage(pkg)
|
||||
else
|
||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||
end
|
||||
@@ -958,7 +991,7 @@ function bl.raycast(start, stop, mask, ignores)
|
||||
local stopS = vecToTs(start)
|
||||
local maskS = maskToTs(mask)
|
||||
local ignoresS = {}
|
||||
for _,v in ipairs(ignores) do
|
||||
for _,v in ipairsNilable(ignores) do
|
||||
table.insert(ignoresS, objToTs(v))
|
||||
end
|
||||
|
||||
@@ -1007,7 +1040,7 @@ end
|
||||
local maxTsArgLen = 8192
|
||||
local function valsToString(vals)
|
||||
local strs = {}
|
||||
for i,v in ipairs(vals) do
|
||||
for i,v in ipairsNilable(vals) do
|
||||
local tstr = table.tostring(v)
|
||||
if #tstr>maxTsArgLen then
|
||||
tstr = tostring(v)
|
||||
|
||||
Reference in New Issue
Block a user