1
0
forked from redo/BlockLua

Merge branch 'master'

This commit is contained in:
2025-12-08 03:09:44 -05:00
8 changed files with 188 additions and 118 deletions

View File

@@ -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)