rework hooks, proper arg conversion for luacall from ts, fix+rename bl.addServerCmd/addClientCmd, remove 'bool' from ts.type (only use 'boolean'), more dedefault typedefs, support typedefs on named objects, typedef inheritance, reorganize libts
This commit is contained in:
@@ -106,21 +106,29 @@ local function valToTs(val)
|
||||
error('valToTs: could not convert '..type(val), 3)
|
||||
end
|
||||
end
|
||||
local function convertValFromTs(val, typ)
|
||||
if typ=='boolean' then
|
||||
return tsBool(val)
|
||||
elseif typ=='object' then
|
||||
return toTsObject(val)
|
||||
else
|
||||
error('valFromTs: invalid force type '..typ, 4)
|
||||
end
|
||||
end
|
||||
bl._forceType = bl._forceType or {}
|
||||
local function valFromTs(val, name)
|
||||
local function valFromTs(val, name, name2) -- todo: ensure name and name2 are already lowercase
|
||||
if type(val)~='string' then
|
||||
error('valFromTs: expected string, got '..type(val), 3) end
|
||||
if name then
|
||||
local nameL = name:lower()
|
||||
if bl._forceType[nameL] then
|
||||
local typ = bl._forceType[nameL]
|
||||
if typ=='boolean' then
|
||||
return tsBool(val)
|
||||
elseif typ=='object' then
|
||||
return toTsObject(val)
|
||||
else
|
||||
error('valFromTs: invalid force type '..typ, 3)
|
||||
end
|
||||
name = name:lower()
|
||||
if bl._forceType[name] then
|
||||
return convertValFromTs(val, bl._forceType[name])
|
||||
end
|
||||
end
|
||||
if name2 then
|
||||
name2 = name2:lower()
|
||||
if bl._forceType[name2] then
|
||||
return convertValFromTs(val, bl._forceType[name2])
|
||||
end
|
||||
end
|
||||
-- '' -> nil
|
||||
@@ -151,22 +159,35 @@ end
|
||||
local function arglistToTs(args)
|
||||
return map(args, valToTs)
|
||||
end
|
||||
function bl.type(name, typ)
|
||||
if typ~='bool' and typ~='boolean' and typ~='object' and typ~=nil then
|
||||
error('bl.type: can only set type to \'bool\' or \'object\' or nil', 2) end
|
||||
if not isValidFuncNameNsArgn(name) then
|
||||
error('bl.type: invalid function or variable name \''..name..'\'', 2) end
|
||||
if typ=='bool' then typ='boolean' end
|
||||
|
||||
bl._forceType[name:lower()] = typ
|
||||
-- apply to children (wip)
|
||||
--local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||
--if not class then
|
||||
-- class, rest = name:match('^([a-zA-Z0-9_]+)(%..+)$') end
|
||||
--if class then
|
||||
--
|
||||
--end
|
||||
local function classFromForceTypeStr(name)
|
||||
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||
if not class then
|
||||
class, rest = name:match('^([a-zA-Z0-9_]+)(%..+)$') end
|
||||
return class,rest
|
||||
end
|
||||
local setForceType
|
||||
setForceType = function(ftname, typ)
|
||||
if typ~='boolean' and typ~='object' and typ~=nil then
|
||||
error('bl.type: can only set type to \'boolean\', \'object\', or nil', 2) end
|
||||
if not isValidFuncNameNsArgn(ftname) then
|
||||
error('bl.type: invalid function or variable name \''..ftname..'\'', 2) end
|
||||
|
||||
ftname = ftname:lower()
|
||||
|
||||
bl._forceType[ftname] = typ
|
||||
|
||||
-- apply to child classes if present
|
||||
local cname, rest = classFromForceTypeStr(ftname)
|
||||
if cname then
|
||||
local meta = bl._objectUserMetas[cname]
|
||||
if meta then
|
||||
for chcname,_ in pairs(meta._children) do
|
||||
setForceType(chcname..rest, typ)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
bl.type = setForceType
|
||||
|
||||
|
||||
-- Value detection
|
||||
@@ -210,40 +231,47 @@ end
|
||||
local tsClassMeta = {
|
||||
__tostring = function(t)
|
||||
return 'torqueClass:'..t._name..
|
||||
(t._inherit and (':'..t._inherit) or '')
|
||||
(t._inherit and (':'..t._inherit._name) or '')
|
||||
end,
|
||||
}
|
||||
bl._objectUserMetas = bl._objectUserMetas or {}
|
||||
function bl.class(name, inherit)
|
||||
if not ( type(name)=='string' and isValidFuncName(name) ) then
|
||||
function bl.class(cname, inhname)
|
||||
if not ( type(cname)=='string' and isValidFuncName(cname) ) then
|
||||
error('bl.class: argument #1: invalid class name', 2) end
|
||||
if not ( inherit==nil or (type(inherit)=='string' and isValidFuncName(inherit)) ) 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
|
||||
name = name:lower()
|
||||
cname = cname:lower()
|
||||
|
||||
local met = bl._objectUserMetas[name] or {
|
||||
_name = name,
|
||||
local met = bl._objectUserMetas[cname] or {
|
||||
_name = cname,
|
||||
_inherit = nil,
|
||||
_children = {},
|
||||
}
|
||||
bl._objectUserMetas[name] = met
|
||||
bl._objectUserMetas[cname] = met
|
||||
setmetatable(met, tsClassMeta)
|
||||
|
||||
if inherit then
|
||||
inherit = inherit:lower()
|
||||
if inhname then
|
||||
inhname = inhname:lower()
|
||||
|
||||
local inh = bl._objectUserMetas[inherit]
|
||||
if not inh then error('bl.class: argument #2: \''..inherit..'\' is not the '..
|
||||
local inh = bl._objectUserMetas[inhname]
|
||||
if not inh then error('bl.class: argument #2: \''..inhname..'\' is not the '..
|
||||
'name of an existing class', 2) end
|
||||
|
||||
inh._children[name] = true
|
||||
inh._children[cname] = true
|
||||
|
||||
local inhI = met._inherit
|
||||
if inhI and inhI~=inh then
|
||||
error('bl.class: argument #2: class already exists and '..
|
||||
'inherits a different parent.', 2) end
|
||||
|
||||
met._inherit = inh
|
||||
|
||||
-- apply inherited method and field types
|
||||
for ftname, typ in pairs(bl._forceType) do
|
||||
local cname2, rest = classFromForceTypeStr(ftname)
|
||||
if cname2==inhname then
|
||||
setForceType(cname..rest, typ)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local function objectInheritedMetas(name)
|
||||
@@ -279,11 +307,15 @@ local tsObjectMeta = {
|
||||
return function(t, ...)
|
||||
local args = {...}
|
||||
local argsS = arglistToTs(args)
|
||||
return valFromTs(_bllua_ts.callobj(rawget(t,'_tsObjectId'), name, unpack(argsS)),
|
||||
return valFromTs(
|
||||
_bllua_ts.callobj(rawget(t,'_tsObjectId'), name, unpack(argsS)),
|
||||
rawget(t,'_tsName') and rawget(t,'_tsName')..'::'..name,
|
||||
rawget(t,'_tsNamespace')..'::'..name)
|
||||
end
|
||||
else
|
||||
return valFromTs(_bllua_ts.getfield(rawget(t,'_tsObjectId'), name),
|
||||
return valFromTs(
|
||||
_bllua_ts.getfield(rawget(t,'_tsObjectId'), name),
|
||||
rawget(t,'_tsName') and rawget(t,'_tsName')..'.'..name,
|
||||
rawget(t,'_tsNamespace')..'.'..name)
|
||||
end
|
||||
end
|
||||
@@ -489,7 +521,7 @@ local tsMeta = {
|
||||
-- bl.set(name, value)
|
||||
-- Used to set global variables
|
||||
function bl.set(name, val)
|
||||
_bllua_ts.call('_bllua_set_var', name, valToTs(val))
|
||||
_bllua_ts.setvar(name, valToTs(val))
|
||||
end
|
||||
|
||||
-- Utility functions
|
||||
@@ -499,7 +531,7 @@ function bl.call(func, ...)
|
||||
return _bllua_ts.call(func, unpack(argsS))
|
||||
end
|
||||
function bl.eval(code)
|
||||
return valFromTs(_bllua_ts.call('eval', code))
|
||||
return valFromTs(_bllua_ts.eval(code))
|
||||
end
|
||||
function bl.exec(file)
|
||||
return valFromTs(_bllua_ts.call('exec', file))
|
||||
@@ -524,8 +556,13 @@ function bl.array(name, ...)
|
||||
local rest = {...}
|
||||
return name..table.concat(rest, '_')
|
||||
end
|
||||
function _bllua_call(name, ...)
|
||||
-- todo: call ts->lua using this instead of directly
|
||||
function _bllua_call(fnameS, ...)
|
||||
local args = arglistFromTs(fnameS:lower(), {...})
|
||||
if not _G[fnameS] then
|
||||
error('luacall: no global lua function named \''..fnameS..'\'') end
|
||||
-- todo: library fields and object methods
|
||||
local res = _G[fnameS](args)
|
||||
return valToTs(res)
|
||||
end
|
||||
|
||||
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
||||
@@ -544,7 +581,7 @@ function bl.schedule(time, cb, ...)
|
||||
bl._scheduleNextId = bl._scheduleNextId+1
|
||||
local args = {...}
|
||||
local handle = tonumber(_bllua_ts.call('schedule',
|
||||
time, 0, 'luacall', '_bllua_schedule_callback', id))
|
||||
time, 0, '_bllua_luacall', '_bllua_schedule_callback', id))
|
||||
local sch = {
|
||||
callback = cb,
|
||||
args = args,
|
||||
@@ -554,8 +591,9 @@ function bl.schedule(time, cb, ...)
|
||||
bl._scheduleTable[id] = sch
|
||||
return sch
|
||||
end
|
||||
function _bllua_schedule_callback(id)
|
||||
id = tonumber(id) or error('_bllua_schedule_callback: invalid id: '..tostring(id))
|
||||
function _bllua_schedule_callback(idS)
|
||||
local id = tonumber(idS) or
|
||||
error('_bllua_schedule_callback: invalid id: '..tostring(idS))
|
||||
local sch = bl._scheduleTable[id]
|
||||
if not sch then error('_bllua_schedule_callback: no schedule with id '..id) end
|
||||
bl._scheduleTable[id] = nil
|
||||
@@ -563,26 +601,48 @@ function _bllua_schedule_callback(id)
|
||||
end
|
||||
|
||||
-- serverCmd and clientCmd
|
||||
-- bl.serverCmd('suicide', function(client) client.player:kill() end)
|
||||
bl._cmds = bl._cmds or {}
|
||||
function _bllua_process_cmd(cmdS, clientS, ...)
|
||||
local client = toTsObject(clientS)
|
||||
local argsS = {...}
|
||||
local args = arglistFromTs(cmdS, argsS)
|
||||
local func = bl._cmds[cmdS]
|
||||
function _bllua_process_cmd(cmdS, ...)
|
||||
local cmd = cmdS:lower()
|
||||
local args = arglistFromTs(cmd, {...})
|
||||
local func = bl._cmds[cmd]
|
||||
if not func then error('_bllua_process_cmd: no cmd named \''..cmd..'\'') end
|
||||
pcall(func, client, unpack(args))
|
||||
func(unpack(args)) --pcall(func, unpack(args))
|
||||
end
|
||||
local function addCmd(cmd, func)
|
||||
if not isValidFuncName(cmd) then
|
||||
error('addCmd: invalid function name \''..tostring(cmd)..'\'') end
|
||||
bl._servercmds[cmd] = func
|
||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h'
|
||||
_bllua_ts.eval('function '..cmd..'(%cl,'..arglist..'){'..
|
||||
'luacall(_bllua_process_cmd,"'..cmd..'",%cl,'..arglist..');}')
|
||||
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..');}')
|
||||
end
|
||||
function bl.addServerCmd(name, func)
|
||||
name = name:lower()
|
||||
addCmd('servercmd'..name, func)
|
||||
bl._forceType['servercmd'..name..':1'] = 'object'
|
||||
end
|
||||
function bl.addClientCmd(name, func)
|
||||
name = name:lower()
|
||||
addCmd('clientcmd'..name, func)
|
||||
end
|
||||
|
||||
-- commandToServer and commandToClient
|
||||
function bl.commandToServer(cmd, ...)
|
||||
_bllua_ts.call('commandToServer',
|
||||
_bllua_ts.call('addTaggedString', cmd),
|
||||
unpack(arglistToTs({...})))
|
||||
end
|
||||
function bl.commandToClient(cmd, ...)
|
||||
_bllua_ts.call('commandToClient',
|
||||
_bllua_ts.call('addTaggedString', cmd),
|
||||
unpack(arglistToTs({...})))
|
||||
end
|
||||
function bl.commandToAll(cmd, ...)
|
||||
_bllua_ts.call('commandToAll',
|
||||
_bllua_ts.call('addTaggedString', cmd),
|
||||
unpack(arglistToTs({...})))
|
||||
end
|
||||
function bl.serverCmd(name, func) addCmd('serverCmd'..name, func) end
|
||||
function bl.clientCmd(name, func) addCmd('clientCmd'..name, func) end
|
||||
|
||||
-- Hooks (using TS packages)
|
||||
local function isPackageActive(pkg)
|
||||
@@ -603,42 +663,67 @@ 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(pkgS, nameS, timeS, ...)
|
||||
local argsS = {...}
|
||||
local args = arglistFromTs(nameS, argsS)
|
||||
|
||||
function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||
local args = arglistFromTs(nameS, {...})
|
||||
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
||||
bl._hooks[pkgS][nameS][timeS]
|
||||
bl._hooks[pkgS][nameS].before
|
||||
if not func then
|
||||
error('_bllua_process_hook: no hook for '..pkgS..':'..nameS..':'..timeS) end
|
||||
|
||||
pcall(func, args)
|
||||
error('_bllua_process_hook_before: no hook for '..pkgs..':'..nameS) end
|
||||
_bllua_ts.setvar('_bllua_hook_abort', '0')
|
||||
func(args) --pcall(func, args)
|
||||
if args._return then
|
||||
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
||||
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
||||
end
|
||||
for i=1,hookNargs do
|
||||
_bllua_ts.setvar('_bllua_hook_arg'..i, valToTs(args[i]))
|
||||
end
|
||||
end
|
||||
function _bllua_process_hook_after(pkgS, nameS, resultS, ...)
|
||||
nameS = nameS:lower()
|
||||
local args = arglistFromTs(nameS, {...})
|
||||
args._return = valFromTs(resultS, nameS)
|
||||
local func = bl._hooks[pkgS] and bl._hooks[pkgS][nameS] and
|
||||
bl._hooks[pkgS][nameS].after
|
||||
if not func then
|
||||
error('_bllua_process_hook_after: no hook for '..pkgs..':'..nameS) end
|
||||
func(args) --pcall(func, args)
|
||||
return valToTs(args._return)
|
||||
end
|
||||
local function updateHook(pkg, name, hk)
|
||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h'
|
||||
local beforeCode = hk.before and
|
||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
||||
'", "before", '..arglist..');') or ''
|
||||
local parentCode = hk.override and
|
||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
||||
'", "override", '..arglist..');') or
|
||||
(tsIsFunctionNsname(name) and
|
||||
('parent::'..name:match('[^:]+$')..'('..arglist..');') or '')
|
||||
('_bllua_luacall("_bllua_process_hook_before", "'..pkg..'","'..name..
|
||||
'",'..hookArglistLocal..');') or ''
|
||||
local arglist = (hk.before and hookArglistGlobal or hookArglistLocal)
|
||||
local parentCode =
|
||||
tsIsFunctionNsname(name) and -- only call parent if it exists
|
||||
(hk.before and
|
||||
'if($_bllua_hook_abort)return $_bllua_hook_return; else ' or '')..
|
||||
((hk.after and '%result=' or 'return ')..
|
||||
'parent::'..name:match('[^:]+$')..
|
||||
'('..arglist..');') or ''
|
||||
local afterCode = hk.after and
|
||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
||||
'", "after", '..arglist..');') or ''
|
||||
bl.eval('package '..pkg..'{function '..name..'('..arglist..'){'..
|
||||
beforeCode..parentCode..afterCode..'}};')
|
||||
('return _bllua_luacall("_bllua_process_hook_after","'..pkg..'","'..name..'",%result,'..
|
||||
arglist..');') or ''
|
||||
local code =
|
||||
'package '..pkg..'{'..
|
||||
'function '..name..'('..hookArglistLocal..'){'..
|
||||
beforeCode..parentCode..afterCode..
|
||||
'}'..
|
||||
'};'
|
||||
_bllua_ts.eval(code)
|
||||
end
|
||||
function bl.hook(pkg, name, time, func)
|
||||
if not isValidFuncName(pkg) then
|
||||
error('bl.hook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
||||
if not isValidFuncNameNs(name) then
|
||||
error('bl.hook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
||||
if time~='before' and time~='after' and time~='override' then
|
||||
error('bl.hook: argument #3: time must be one of '..
|
||||
'\'before\' \'after\' \'override\'', 2) end
|
||||
if time~='before' and time~='after' then
|
||||
error('bl.hook: argument #3: time must be \'before\' or \'after\'', 2) end
|
||||
if type(func)~='function' then
|
||||
error('bl.hook: argument #4: expected a function', 2) end
|
||||
|
||||
@@ -654,9 +739,8 @@ function bl.unhook(pkg, name, time)
|
||||
error('bl.unhook: argument #1: invalid package name \''..tostring(pkg)..'\'', 2) end
|
||||
if not isValidFuncNameNs(name) then
|
||||
error('bl.unhook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
||||
if time~='before' and time~='after' and time~='override' then
|
||||
error('bl.unhook: argument #3: time must be one of '..
|
||||
'\'before\' \'after\' \'override\'', 2) end
|
||||
if time~='before' and time~='after' then
|
||||
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2) end
|
||||
|
||||
if not name then
|
||||
if bl._hooks[pkg] then
|
||||
@@ -679,15 +763,16 @@ function bl.unhook(pkg, name, time)
|
||||
end
|
||||
updateHook(pkg, name, {})
|
||||
else
|
||||
if time~='before' and time~='after' and time~='override' then
|
||||
error('bl.unhook: argument #3: time must be nil or one of '..
|
||||
'\'before\' \'after\' \'override\'', 2) end
|
||||
if time~='before' and time~='after' then
|
||||
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2) end
|
||||
bl._hooks[pkg][name][time] = nil
|
||||
if table.empty(bl._hooks[pkg][name]) and table.empty(bl._hooks[pkg]) then
|
||||
bl._hooks[pkg] = nil
|
||||
deactivatePackage(pkg)
|
||||
updateHook(pkg, name, {})
|
||||
else
|
||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||
end
|
||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||
end
|
||||
else
|
||||
--error('bl.unhook: no hooks registered for function \''..name..
|
||||
|
||||
Reference in New Issue
Block a user