Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -4,7 +4,10 @@ cd /d %~dp0
|
|||||||
set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++
|
set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++
|
||||||
|
|
||||||
echo on
|
echo on
|
||||||
g++ src/bllua4.cpp %buildargs% -o BlockLua.dll && g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll
|
|
||||||
|
g++ src/bllua4.cpp %buildargs% -o BlockLua.dll
|
||||||
|
@rem g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll
|
||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
rem objdump -d BlockLua.dll > BlockLua.dll.dump.txt
|
rem objdump -d BlockLua.dll > BlockLua.dll.dump.txt
|
||||||
|
|||||||
BIN
lua5.1.dll
BIN
lua5.1.dll
Binary file not shown.
148
readme.md
148
readme.md
@@ -37,27 +37,45 @@ Lua scripting for Blockland
|
|||||||
`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 childIndex, child in object:members() do` - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
|
||||||
|
|
||||||
### Advanced
|
### Timing/Schedules
|
||||||
`sched = bl.schedule(timeMs, function, args...)` - Schedule a Lua function to be called later, similar to schedule in Torque
|
`sched = bl.schedule(timeMs, function, args...)` - Schedule a Lua function to be called later, similar to schedule in Torque
|
||||||
`sched:cancel()` - Cancel a previously scheduled timer
|
`sched:cancel()` - Cancel a previously scheduled timer
|
||||||
`hitObject, hisPos, hitNormal = bl.raycast(vector{startPosX,y,z}, vector{endPosX,y,z}, 'objtype'/{'objtypes',...}, ignoreObjects...?)` - Cast a ray in the world over objects of the specified type(s) (possibly excluding some objects), and return the object hit, the position of the hit, and the normal vector to the surface hit. See the Types section for a list of valid object types.
|
|
||||||
|
### Raycasts and Searches
|
||||||
|
`hitObject, hitPos, hitNormal = bl.raycast(vector{startPosX,y,z}, vector{endPosX,y,z}, 'objtype'/{'objtypes',...}, ignoreObjects...?)` - Cast a ray in the world over objects of the specified type(s) (possibly excluding some objects), and return the object hit, the position of the hit, and the normal vector to the surface hit. 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.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.
|
||||||
`bl.serverCmd('commandName', function(client, args...) code() end)` - Register a /-command on the server
|
|
||||||
`bl.clientCmd('commandName', function(args...) code() end)` - Register a client command on the client
|
### Server-Client Communication
|
||||||
|
`bl.addServerCmd('commandName', function(client, args...) yourCode end)` - Register a /command on the server
|
||||||
|
`bl.addClientCmd('commandName', function(args...) yourCode end)` - Register a client command on the client
|
||||||
|
`bl.commandToServer('commandName', args...)` - Execute a server command as a client
|
||||||
|
`bl.commandToClient('commandName', args...)` - As the server, execute a client command on a specific client
|
||||||
|
`bl.commandToAll('commandName', args...)` - As the server, execute a client command on all clients
|
||||||
|
|
||||||
### Packages/Hooks
|
### Packages/Hooks
|
||||||
`bl.hook('packageName', 'functionName', 'before'/'after'/'override', function(args...) code() end)` - Hook a Torque function with a Lua function
|
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) yourCode end)` - Hook a Torque function with a Lua function.
|
||||||
`bl.unhook('packageName', 'functionName', 'before'/'after'/'override')` - Remove a previously defined hook
|
`args` is an array containing the arguments provided to the function. If the hook is `before`, these can be modified before being passed to the parent function.
|
||||||
|
If `args._return` is set to anything other than nil by a `before` hook, the parent function will not be called, and the function will simply return that value. Also in this case, any `after` hook will not be executed.
|
||||||
|
In an `after` hook, `args._return` is set to the value returned by the parent function, and can be modified.
|
||||||
|
`bl.unhook('packageName', 'functionName', 'before'/'after')` - Remove a previously defined hook
|
||||||
|
`bl.unhook('packageName', 'functionName')` - Remove any previously defined hooks on the function within the package
|
||||||
|
`bl.unhook('packageName')` - Remove any previously defined hooks within the package
|
||||||
|
|
||||||
### Classes and Types
|
### Modules and Dependencies
|
||||||
`bl.bool(thing)` - Convert a Torque boolean (0 or 1) into a Lua boolean. Done automatically for all built-in functions that return bools.
|
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
|
||||||
`bl.object(thing)` - Convert a Torque object reference (object ID or name) into a Lua object. Done automatically for all built-in functions that return objects.
|
|
||||||
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic.
|
`require('modulePath.moduleName')` - Load a Lua file or external library.
|
||||||
`bl.type('funcName', 'type')` - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all built-in functions that return objects.
|
`require` replaces `.` with `/` in the path, and then searches for files in the following order:
|
||||||
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
|
- `./modulePath/moduleName.lua`
|
||||||
`bl.class('className')` - Register a Torque class to be used from Lua (Already done for all built-in classes)
|
- `./modulePath/moduleName/init.lua`
|
||||||
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
- `modulePath/moduleName.lua` (Relative to game directory)
|
||||||
|
- `modulePath/moduleName/init.lua` (Relative to game directory)
|
||||||
|
- `modules/lualib/modulePath/moduleName.lua`
|
||||||
|
- `modules/lualib/modulePath/moduleName/init.lua`
|
||||||
|
- `modules/lualib/modulePath/moduleName.dll` - C libraries for Lua can be loaded
|
||||||
|
|
||||||
|
Like in standard Lua, modules loaded using `require` are only executed the first time `require` is called with that path (from anywhere). Subsequent calls simply return the result from the initial execution. To allow hot reloading, use `dofile`.
|
||||||
|
|
||||||
### File I/O
|
### File I/O
|
||||||
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
|
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
|
||||||
@@ -69,26 +87,84 @@ Relative paths (`./`) are allowed. `..` is not allowed.
|
|||||||
Reading files from ZIPs is supported, with caveats. Null characters are not allowed, and \r\n becomes \n. Generally, text formats work, and binary formats don't.
|
Reading files from ZIPs is supported, with caveats. Null characters are not allowed, and \r\n becomes \n. Generally, text formats work, and binary formats don't.
|
||||||
When reading from outside ZIPs, binary files are fully supported.
|
When reading from outside ZIPs, binary files are fully supported.
|
||||||
|
|
||||||
### Modules and Dependencies
|
### Object Creation
|
||||||
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
|
`bl.new('className')` - Create a new Torque object
|
||||||
|
`bl.new('className', {fieldName = value, ...})` - Create a new Torque object with the given fields
|
||||||
|
`bl.new('className objectName', fields?)` - Create a new named Torque object
|
||||||
|
`bl.new('className objectName:parentName', fields?)` - Create a new named Torque object with inheritance
|
||||||
|
`bl.datablock('datablockClassName datablockName', fields?)` - Create a new datablock
|
||||||
|
`bl.datablock('datablockClassName datablockName:parentDatablockName', fields?)` - Create a new datablock with inheritance
|
||||||
|
|
||||||
`require('modulePath.moduleName')` - Load a Lua file or or external library.
|
### Classes and Types
|
||||||
Require replaces `.` with `/` in the path, and then searches for files in the following order:
|
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', and nil (default is nil, which applies automatic conversion).
|
||||||
- `./modulePath/moduleName.lua`
|
`bl.type('funcName', 'type')` - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all default functions.
|
||||||
- `./modulePath/moduleName/init.lua`
|
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
|
||||||
- `modulePath/moduleName.lua` (Relative to game directory)
|
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
|
||||||
- `modulePath/moduleName/init.lua` (Relative to game directory)
|
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
||||||
- `modules/lualib/modulePath/moduleName.lua`
|
`bl.boolean(thing)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
|
||||||
- `modules/lualib/modulePath/moduleName/init.lua`
|
`bl.object(thing)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
|
||||||
- `modules/lualib/modulePath/moduleName.dll`
|
|
||||||
|
|
||||||
Like in standard Lua, modules loaded using `require` are only executed the first time `require` is called with that path. Subsequent calls simply return the result from the initial execution. To allow hot reloading, use `dofile`.
|
### Vectors
|
||||||
|
`vec = vector{x,y,z}` - Create a vector. Can have any number of elements
|
||||||
|
`vec1 + vec2` - Add
|
||||||
|
`vec1 - vec2` - Subtract
|
||||||
|
`vec * number` - Scale (x\*n, y\*n, z\*n)
|
||||||
|
`vec / number` - Scale (x/n, y/n, z/n)
|
||||||
|
`vec ^ number` - Exponentiate (x^n, y^n, z^n)
|
||||||
|
`vec1 * vec2` - Multiply elements piecewise (x1\*x2, y1\*y2, z1\*z2)
|
||||||
|
`vec1 / vec2` - Divide elements piecewise (x1/x2, y1/y2, z1/z2)
|
||||||
|
`vec1 ^ vec2` - Exponentiate elements piecewise (x1^x2, y1^y2, z1^z2)
|
||||||
|
`-vec` - Negate/invert
|
||||||
|
`vec1 == vec2` - Compare by value
|
||||||
|
`vec:length()` - Length
|
||||||
|
`vec:normalize()` - Preserve direction but scale so magnitude is 1
|
||||||
|
`vec:floor()` - Floor each element
|
||||||
|
`vec:ceil()` - Ceil each element
|
||||||
|
`vec:abs()` - Absolute value each element
|
||||||
|
`vec1:dot(vec2)` - Dot product
|
||||||
|
`vec1:cross(vec2)` - Cross product (Only defined for two vectors of length 3)
|
||||||
|
`vec:rotateZ(radians)` - Rotate counterclockwise about the Z (vertical) axis
|
||||||
|
`vec:rotateByAngleId(0/1/2/3)` - Rotate counterclockwise about the Z (vertical) axis in increments of 90 degrees
|
||||||
|
`vec:tsString()` - Convert to string usable by Torque. Done automatically when a vector is passed to Torque.
|
||||||
|
`vec1:distance(vec2)` - Distance between two points
|
||||||
|
`vec2 = vec:copy()` - Clone a vector so its elements can be modified without affecting the original. Usually not needed - the builtin vector functions never modify vectors in-place.
|
||||||
|
|
||||||
|
### Extended Standard Lua Library
|
||||||
|
`string[index]`
|
||||||
|
`string[{start,stop}]`
|
||||||
|
`string.split(str, separator='' (splits into chars), noregex=false)`
|
||||||
|
`string.bytes(str)`
|
||||||
|
`string.trim(str, charsToTrim=' \t\r\n')`
|
||||||
|
`table.empty`
|
||||||
|
`table.map(func, ...)`
|
||||||
|
`table.map_list(func, ...)`
|
||||||
|
`table.swap(tbl)`
|
||||||
|
`table.reverse(list)`
|
||||||
|
`table.islist(list)`
|
||||||
|
`table.append(list, ...)`
|
||||||
|
`table.join(...)`
|
||||||
|
`table.contains(tbl, val)`
|
||||||
|
`table.contains_list(list, val)`
|
||||||
|
`table.copy(tbl)`
|
||||||
|
`table.copy_list(list)`
|
||||||
|
`table.sortcopy(tbl, sortFunction?)`
|
||||||
|
`table.removevalue(tbl, val)`
|
||||||
|
`table.removevalue_list(tbl, val)`
|
||||||
|
`table.tostring(tbl)`
|
||||||
|
`for char in string.chars(str) do`
|
||||||
|
`string.escape(str, escapes={['\n']='\\n', etc. (C standard)})`
|
||||||
|
`string.unescape(str, escapeChar='\\', unescapes={['\\n']='\n', etc.})`
|
||||||
|
`io.readall(filename)`
|
||||||
|
`io.writeall(filename, str)`
|
||||||
|
`math.round(num)`
|
||||||
|
`math.mod(divisor, modulus)`
|
||||||
|
`math.clamp(num, min, max)`
|
||||||
|
|
||||||
## Type Conversion
|
## Type Conversion
|
||||||
When a TorqueScript function is called from Lua or vice-versa, the arguments and return value must be converted between the two languages' type systems.
|
When a TorqueScript function is called from Lua or vice-versa, the arguments and return value must be converted between the two languages' type systems.
|
||||||
TorqueScript stores no type information; all values in TorqueScript are strings. So it's necessary to make some inferences when converting values between the two languages.
|
TorqueScript stores no type information; all values in TorqueScript are strings. So it's necessary to make some inferences when converting values between the two languages.
|
||||||
### From TorqueScript to Lua
|
### From TorqueScript to Lua
|
||||||
- Any numeric value becomes a Lua `number`, except as specified with `ts.type`, which may convert a value into a `boolean` or a Torque object container.
|
- 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`
|
||||||
- A string containing three numbers separated by spaces becomes a `vector`
|
- A string containing three numbers separated by spaces becomes a `vector`
|
||||||
- A string containing six numbers separated by spaces becomes a table of two vectors
|
- A string containing six numbers separated by spaces becomes a table of two vectors
|
||||||
@@ -106,17 +182,17 @@ TorqueScript stores no type information; all values in TorqueScript are strings.
|
|||||||
All Lua code is sandboxed, and file access is confied to the default directories in the same way TorqueScript is.
|
All Lua code is sandboxed, and file access is confied to the default directories in the same way TorqueScript is.
|
||||||
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
|
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-Unsafe.dll can be used in place of BlockLua.dll, to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi.
|
BlockLua-Unsafe.dll can be built and used in place of BlockLua.dll (see compile.bat), to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi.
|
||||||
Please do not publish add-ons that require unsafe mode.
|
Please do not publish add-ons that require unsafe mode.
|
||||||
|
|
||||||
## Other Reference
|
## Other Reference
|
||||||
|
|
||||||
### List of Object Types
|
### List of Object Types
|
||||||
'all' - Any object
|
`'all'` - Any object
|
||||||
'brick' - Bricks with Ray-Casting enabled
|
`'player'` - Players or bots
|
||||||
'brickalways' - All bricks including those with Ray-Casting disabled
|
`'item'` - Items
|
||||||
'player' - Players or bots
|
`'vehicle'` - Vehicles
|
||||||
'item' - Items
|
`'projectile'` - Projectiles
|
||||||
'vehicle' - Vehicles
|
`'brick'` - Bricks with raycasting enabled
|
||||||
'projectile' - Projectiles
|
`'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'
|
Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'`
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ INCLUDE_BIN(bll_fileLuaEnv , "lua-env.lua");
|
|||||||
INCLUDE_BIN(bll_fileTsEnv , "ts-env.cs" );
|
INCLUDE_BIN(bll_fileTsEnv , "ts-env.cs" );
|
||||||
INCLUDE_BIN(bll_fileLuaStd , "util/std.lua");
|
INCLUDE_BIN(bll_fileLuaStd , "util/std.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaVector , "util/vector.lua");
|
INCLUDE_BIN(bll_fileLuaVector , "util/vector.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaLibts , "util/libts.lua");
|
INCLUDE_BIN(bll_fileLuaLibts , "util/libts-lua.lua");
|
||||||
INCLUDE_BIN(bll_fileTsLibtsSupport, "util/libts-support.cs");
|
INCLUDE_BIN(bll_fileTsLibts , "util/libts-ts.cs");
|
||||||
INCLUDE_BIN(bll_fileLuaLibbl , "util/libbl.lua" );
|
INCLUDE_BIN(bll_fileLuaLibbl , "util/libbl.lua" );
|
||||||
INCLUDE_BIN(bll_fileLuaLibblTypes , "util/libbl-types.lua");
|
INCLUDE_BIN(bll_fileLuaLibblTypes , "util/libbl-types.lua");
|
||||||
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
|
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
|
||||||
@@ -68,7 +68,7 @@ bool init() {
|
|||||||
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
||||||
BlEval(bll_fileTsLibtsSupport);
|
BlEval(bll_fileTsLibts);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
||||||
BlEval(bll_fileTsLibblSupport);
|
BlEval(bll_fileTsLibblSupport);
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
// Built-in functions
|
|
||||||
// Eval'd after BLLua4 has loaded the Lua environment and API
|
|
||||||
|
|
||||||
// Public Lua library for TS
|
|
||||||
function luacall(%func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall(%func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p);
|
|
||||||
}
|
|
||||||
function luaexec(%fn) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_exec", %fn);
|
|
||||||
}
|
|
||||||
function luaeval(%code) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_eval", %code);
|
|
||||||
}
|
|
||||||
function luaget(%name) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_getvar", %name);
|
|
||||||
}
|
|
||||||
function luaset(%name, %val) {
|
|
||||||
if($_bllua_active)
|
|
||||||
_bllua_luacall("_bllua_setvar", %name, %val);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo(" Executed bllua-env.cs");
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ package _bllua_smartEval {
|
|||||||
if($_bllua_active) {
|
if($_bllua_active) {
|
||||||
%text = getSubStr(%text, 1, strLen(%text));
|
%text = getSubStr(%text, 1, strLen(%text));
|
||||||
echo("Lua ==> " @ %text);
|
echo("Lua ==> " @ %text);
|
||||||
luacall("_bllua_smarteval", %text);
|
_bllua_luacall("_bllua_smarteval", %text);
|
||||||
} else {
|
} else {
|
||||||
echo("Lua: not loaded");
|
echo("Lua: not loaded");
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,8 @@ package _bllua_objectDeletionHook {
|
|||||||
// note: no parent function exists by default,
|
// note: no parent function exists by default,
|
||||||
// and this is loaded before any addons
|
// and this is loaded before any addons
|
||||||
//parent::onRemove(%obj);
|
//parent::onRemove(%obj);
|
||||||
if($_bllua_active) luacall("_bllua_objectDeleted", %obj);
|
// assuming obj is an ID and never a name
|
||||||
|
if($_bllua_active) _bllua_luacall("_bllua_objectDeleted", %obj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
activatePackage(_bllua_objectDeletionHook);
|
activatePackage(_bllua_objectDeletionHook);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -106,21 +106,29 @@ local function valToTs(val)
|
|||||||
error('valToTs: could not convert '..type(val), 3)
|
error('valToTs: could not convert '..type(val), 3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
bl._forceType = bl._forceType or {}
|
local function convertValFromTs(val, typ)
|
||||||
local function valFromTs(val, name)
|
|
||||||
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
|
if typ=='boolean' then
|
||||||
return tsBool(val)
|
return tsBool(val)
|
||||||
elseif typ=='object' then
|
elseif typ=='object' then
|
||||||
return toTsObject(val)
|
return toTsObject(val)
|
||||||
else
|
else
|
||||||
error('valFromTs: invalid force type '..typ, 3)
|
error('valFromTs: invalid force type '..typ, 4)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
bl._forceType = bl._forceType or {}
|
||||||
|
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
|
||||||
|
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
|
||||||
end
|
end
|
||||||
-- '' -> nil
|
-- '' -> nil
|
||||||
@@ -151,14 +159,35 @@ end
|
|||||||
local function arglistToTs(args)
|
local function arglistToTs(args)
|
||||||
return map(args, valToTs)
|
return map(args, valToTs)
|
||||||
end
|
end
|
||||||
function bl.type(name,typ)
|
local function classFromForceTypeStr(name)
|
||||||
if typ~='bool' and typ~='boolean' and typ~='object' and typ~=nil then
|
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||||
error('bl.type: can only set type to \'bool\' or \'object\' or nil', 2) end
|
if not class then
|
||||||
if not isValidFuncNameNsArgn(name) then
|
class, rest = name:match('^([a-zA-Z0-9_]+)(%..+)$') end
|
||||||
error('bl.type: invalid function or variable name \''..name..'\'', 2) end
|
return class,rest
|
||||||
if typ=='bool' then typ='boolean' end
|
|
||||||
bl._forceType[name:lower()] = typ
|
|
||||||
end
|
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
|
-- Value detection
|
||||||
@@ -199,31 +228,50 @@ function bl.isFunction(a1, a2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Torque object pseudo-class
|
-- Torque object pseudo-class
|
||||||
|
local tsClassMeta = {
|
||||||
|
__tostring = function(t)
|
||||||
|
return 'torqueClass:'..t._name..
|
||||||
|
(t._inherit and (':'..t._inherit._name) or '')
|
||||||
|
end,
|
||||||
|
}
|
||||||
bl._objectUserMetas = bl._objectUserMetas or {}
|
bl._objectUserMetas = bl._objectUserMetas or {}
|
||||||
function bl.class(name, inherit)
|
function bl.class(cname, inhname)
|
||||||
if not ( type(name)=='string' and isValidFuncName(name) ) 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 ( 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
|
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 {}
|
local met = bl._objectUserMetas[cname] or {
|
||||||
bl._objectUserMetas[name] = met
|
_name = cname,
|
||||||
met._name = name
|
_inherit = nil,
|
||||||
|
_children = {},
|
||||||
|
}
|
||||||
|
bl._objectUserMetas[cname] = met
|
||||||
|
setmetatable(met, tsClassMeta)
|
||||||
|
|
||||||
if inherit then
|
if inhname then
|
||||||
inherit = inherit:lower()
|
inhname = inhname:lower()
|
||||||
|
|
||||||
local inh = bl._objectUserMetas[inherit]
|
local inh = bl._objectUserMetas[inhname]
|
||||||
if not inh then error('bl.class: argument #2: \''..inherit..'\' is not the '..
|
if not inh then error('bl.class: argument #2: \''..inhname..'\' is not the '..
|
||||||
'name of an existing class', 2) end
|
'name of an existing class', 2) end
|
||||||
|
|
||||||
local inhI = bl._objectUserMetas[name]._inherit
|
inh._children[cname] = true
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
bl._objectUserMetas[name]._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
|
||||||
end
|
end
|
||||||
local function objectInheritedMetas(name)
|
local function objectInheritedMetas(name)
|
||||||
@@ -259,11 +307,15 @@ local tsObjectMeta = {
|
|||||||
return function(t, ...)
|
return function(t, ...)
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local argsS = arglistToTs(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)
|
rawget(t,'_tsNamespace')..'::'..name)
|
||||||
end
|
end
|
||||||
else
|
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)
|
rawget(t,'_tsNamespace')..'.'..name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -418,7 +470,7 @@ toTsObject = function(idiS)
|
|||||||
_tsObjectId = _bllua_ts.callobj(idiS, 'getId' ),
|
_tsObjectId = _bllua_ts.callobj(idiS, 'getId' ),
|
||||||
_tsName = _bllua_ts.callobj(idiS, 'getName' ),
|
_tsName = _bllua_ts.callobj(idiS, 'getName' ),
|
||||||
_tsNamespace = className,
|
_tsNamespace = className,
|
||||||
_tsClassName = className:lower()
|
_tsClassName = className:lower(),
|
||||||
}
|
}
|
||||||
setmetatable(obj, tsObjectMeta)
|
setmetatable(obj, tsObjectMeta)
|
||||||
|
|
||||||
@@ -438,7 +490,7 @@ local tsMeta = {
|
|||||||
__index = function(t, name)
|
__index = function(t, name)
|
||||||
if getmetatable(t)[name] then
|
if getmetatable(t)[name] then
|
||||||
return getmetatable(t)[name]
|
return getmetatable(t)[name]
|
||||||
elseif bl._objectUserMetas[name:lower()] then
|
elseif type(name)=='string' and bl._objectUserMetas[name:lower()] then
|
||||||
return bl._objectUserMetas[name:lower()]
|
return bl._objectUserMetas[name:lower()]
|
||||||
else
|
else
|
||||||
if type(name)=='number' then
|
if type(name)=='number' then
|
||||||
@@ -446,7 +498,7 @@ local tsMeta = {
|
|||||||
elseif name:find('::') then
|
elseif name:find('::') then
|
||||||
local ns, rest = name:match('^([^:]+)::(.+)$')
|
local ns, rest = name:match('^([^:]+)::(.+)$')
|
||||||
if not ns then error('ts index: invalid name \''..name..'\'', 2) end
|
if not ns then error('ts index: invalid name \''..name..'\'', 2) end
|
||||||
if not rest:find('::') and tsIsFunction(ns, rest) then -- tsIsFunction is only defined with one argument
|
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
||||||
error('ts index: can\'t call a namespaced function from lua', 2)
|
error('ts index: can\'t call a namespaced function from lua', 2)
|
||||||
else
|
else
|
||||||
return valFromTs(_bllua_ts.getvar(name), name)
|
return valFromTs(_bllua_ts.getvar(name), name)
|
||||||
@@ -469,7 +521,7 @@ local tsMeta = {
|
|||||||
-- bl.set(name, value)
|
-- bl.set(name, value)
|
||||||
-- Used to set global variables
|
-- Used to set global variables
|
||||||
function bl.set(name, val)
|
function bl.set(name, val)
|
||||||
_bllua_ts.call('_bllua_set_var', name, valToTs(val))
|
_bllua_ts.setvar(name, valToTs(val))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Utility functions
|
-- Utility functions
|
||||||
@@ -479,19 +531,19 @@ function bl.call(func, ...)
|
|||||||
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.call('eval', code))
|
return valFromTs(_bllua_ts.eval(code))
|
||||||
end
|
end
|
||||||
function bl.exec(file)
|
function bl.exec(file)
|
||||||
return valFromTs(_bllua_ts.call('exec', file))
|
return valFromTs(_bllua_ts.call('exec', file))
|
||||||
end
|
end
|
||||||
function bl.tobool(val)
|
function bl.boolean(val)
|
||||||
return val~=nil and
|
return val~=nil and
|
||||||
val~=false and
|
val~=false and
|
||||||
--val~='' and
|
--val~='' and
|
||||||
--val~='0' and
|
--val~='0' and
|
||||||
val~=0
|
val~=0
|
||||||
end
|
end
|
||||||
function bl.toobject(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
|
||||||
elseif type(id)=='string' or type(id)=='number' then
|
elseif type(id)=='string' or type(id)=='number' then
|
||||||
@@ -504,8 +556,13 @@ function bl.array(name, ...)
|
|||||||
local rest = {...}
|
local rest = {...}
|
||||||
return name..table.concat(rest, '_')
|
return name..table.concat(rest, '_')
|
||||||
end
|
end
|
||||||
function _bllua_call(name, ...)
|
function _bllua_call(fnameS, ...)
|
||||||
-- todo: call ts->lua using this instead of directly
|
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
|
end
|
||||||
|
|
||||||
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
||||||
@@ -524,7 +581,7 @@ function bl.schedule(time, cb, ...)
|
|||||||
bl._scheduleNextId = bl._scheduleNextId+1
|
bl._scheduleNextId = bl._scheduleNextId+1
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local handle = tonumber(_bllua_ts.call('schedule',
|
local handle = tonumber(_bllua_ts.call('schedule',
|
||||||
time, 0, 'luacall', '_bllua_schedule_callback', id))
|
time, 0, '_bllua_luacall', '_bllua_schedule_callback', id))
|
||||||
local sch = {
|
local sch = {
|
||||||
callback = cb,
|
callback = cb,
|
||||||
args = args,
|
args = args,
|
||||||
@@ -534,38 +591,58 @@ function bl.schedule(time, cb, ...)
|
|||||||
bl._scheduleTable[id] = sch
|
bl._scheduleTable[id] = sch
|
||||||
return sch
|
return sch
|
||||||
end
|
end
|
||||||
function _bllua_schedule_callback(id)
|
function _bllua_schedule_callback(idS)
|
||||||
id = tonumber(id)
|
local id = tonumber(idS) or
|
||||||
if id == nil then
|
error('_bllua_schedule_callback: invalid id: '..tostring(idS))
|
||||||
error('_ts_schedule_callback: invalid id')
|
|
||||||
end
|
|
||||||
local sch = bl._scheduleTable[id]
|
local sch = bl._scheduleTable[id]
|
||||||
if not sch then error('_ts_schedule_callback: no schedule with id '..id) end
|
if not sch then error('_bllua_schedule_callback: no schedule with id '..id) end
|
||||||
bl._scheduleTable[id] = nil
|
bl._scheduleTable[id] = nil
|
||||||
sch.callback(unpack(sch.args))
|
sch.callback(unpack(sch.args))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- serverCmd and clientCmd
|
-- serverCmd and clientCmd
|
||||||
-- bl.serverCmd('suicide', function(client) client.player:kill() end)
|
|
||||||
bl._cmds = bl._cmds or {}
|
bl._cmds = bl._cmds or {}
|
||||||
function _bllua_process_cmd(cmdS, clientS, ...)
|
function _bllua_process_cmd(cmdS, ...)
|
||||||
local client = toTsObject(clientS)
|
local cmd = cmdS:lower()
|
||||||
local argsS = {...}
|
local args = arglistFromTs(cmd, {...})
|
||||||
local args = arglistFromTs(cmdS, argsS)
|
local func = bl._cmds[cmd]
|
||||||
local func = bl._cmds[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
|
||||||
pcall(func, client, 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._servercmds[cmd] = func
|
bl._cmds[cmd] = func
|
||||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h'
|
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p'
|
||||||
_bllua_ts.eval('function '..cmd..'(%cl,'..arglist..'){'..
|
_bllua_ts.eval('function '..cmd..'('..arglist..'){'..
|
||||||
'luacall(_bllua_process_cmd,"'..cmd..'",%cl,'..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
|
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)
|
-- Hooks (using TS packages)
|
||||||
local function isPackageActive(pkg)
|
local function isPackageActive(pkg)
|
||||||
@@ -586,42 +663,67 @@ 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(pkgS, nameS, timeS, ...)
|
function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||||
local argsS = {...}
|
local args = arglistFromTs(nameS, {...})
|
||||||
local args = arglistFromTs(nameS, argsS)
|
|
||||||
|
|
||||||
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][timeS]
|
bl._hooks[pkgS][nameS].before
|
||||||
if not func then
|
if not func then
|
||||||
error('_bllua_process_hook: no hook for '..pkgS..':'..nameS..':'..timeS) end
|
error('_bllua_process_hook_before: no hook for '..pkgs..':'..nameS) end
|
||||||
|
_bllua_ts.setvar('_bllua_hook_abort', '0')
|
||||||
pcall(func, args)
|
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
|
end
|
||||||
local function updateHook(pkg, name, hk)
|
local function updateHook(pkg, name, hk)
|
||||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h'
|
|
||||||
local beforeCode = hk.before and
|
local beforeCode = hk.before and
|
||||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
('_bllua_luacall("_bllua_process_hook_before", "'..pkg..'","'..name..
|
||||||
'", "before", '..arglist..');') or ''
|
'",'..hookArglistLocal..');') or ''
|
||||||
local parentCode = hk.override and
|
local arglist = (hk.before and hookArglistGlobal or hookArglistLocal)
|
||||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
local parentCode =
|
||||||
'", "override", '..arglist..');') or
|
tsIsFunctionNsname(name) and -- only call parent if it exists
|
||||||
(tsIsFunctionNsname(name) and
|
(hk.before and
|
||||||
('parent::'..name:match('[^:]+$')..'('..arglist..');') or '')
|
'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
|
local afterCode = hk.after and
|
||||||
('luacall("_bllua_process_hook", "'..pkg..'", "'..name..
|
('return _bllua_luacall("_bllua_process_hook_after","'..pkg..'","'..name..'",%result,'..
|
||||||
'", "after", '..arglist..');') or ''
|
arglist..');') or ''
|
||||||
bl.eval('package '..pkg..'{function '..name..'('..arglist..'){'..
|
local code =
|
||||||
beforeCode..parentCode..afterCode..'}};')
|
'package '..pkg..'{'..
|
||||||
|
'function '..name..'('..hookArglistLocal..'){'..
|
||||||
|
beforeCode..parentCode..afterCode..
|
||||||
|
'}'..
|
||||||
|
'};'
|
||||||
|
_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' and time~='override' then
|
if time~='before' and time~='after' then
|
||||||
error('bl.hook: argument #3: time must be one of '..
|
error('bl.hook: argument #3: time must be \'before\' or \'after\'', 2) end
|
||||||
'\'before\' \'after\' \'override\'', 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
|
||||||
|
|
||||||
@@ -632,14 +734,16 @@ 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)
|
||||||
|
return next(t)~=nil
|
||||||
|
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) end
|
||||||
if not isValidFuncNameNs(name) then
|
if not isValidFuncNameNs(name) then
|
||||||
error('bl.unhook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
error('bl.unhook: argument #2: invalid function name \''..tostring(name)..'\'', 2) end
|
||||||
if time~='before' and time~='after' and time~='override' then
|
if time~='before' and time~='after' then
|
||||||
error('bl.unhook: argument #3: time must be one of '..
|
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2) end
|
||||||
'\'before\' \'after\' \'override\'', 2) end
|
|
||||||
|
|
||||||
if not name then
|
if not name then
|
||||||
if bl._hooks[pkg] then
|
if bl._hooks[pkg] then
|
||||||
@@ -662,16 +766,17 @@ function bl.unhook(pkg, name, time)
|
|||||||
end
|
end
|
||||||
updateHook(pkg, name, {})
|
updateHook(pkg, name, {})
|
||||||
else
|
else
|
||||||
if time~='before' and time~='after' and time~='override' then
|
if time~='before' and time~='after' then
|
||||||
error('bl.unhook: argument #3: time must be nil or one of '..
|
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2) end
|
||||||
'\'before\' \'after\' \'override\'', 2) end
|
|
||||||
bl._hooks[pkg][name][time] = nil
|
bl._hooks[pkg][name][time] = nil
|
||||||
if table.empty(bl._hooks[pkg][name]) and table.empty(bl._hooks[pkg]) then
|
if tableEmpty(bl._hooks[pkg][name]) and tableEmpty(bl._hooks[pkg]) then
|
||||||
bl._hooks[pkg] = nil
|
bl._hooks[pkg] = nil
|
||||||
deactivatePackage(pkg)
|
deactivatePackage(pkg)
|
||||||
end
|
updateHook(pkg, name, {})
|
||||||
|
else
|
||||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||||
end
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
--error('bl.unhook: no hooks registered for function \''..name..
|
--error('bl.unhook: no hooks registered for function \''..name..
|
||||||
-- '\' under package name \''..pkg..'\'', 2)
|
-- '\' under package name \''..pkg..'\'', 2)
|
||||||
@@ -769,10 +874,15 @@ function bl.radiusSearch(pos, radius, mask)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Print/Talk/Echo
|
-- Print/Talk/Echo
|
||||||
|
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 ipairs(vals) do
|
||||||
strs[i] = table.tostring(v)
|
local tstr = table.tostring(v)
|
||||||
|
if #tstr>maxTsArgLen then
|
||||||
|
tstr = tostring(v)
|
||||||
|
end
|
||||||
|
strs[i] = tstr
|
||||||
end
|
end
|
||||||
return table.concat(strs, ' ')
|
return table.concat(strs, ' ')
|
||||||
end
|
end
|
||||||
@@ -787,11 +897,12 @@ bl.talk = function(...)
|
|||||||
_bllua_ts.call('talk', str)
|
_bllua_ts.call('talk', str)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- bl.new and bl.datablock
|
||||||
local function createTsObj(keyword, class, name, inherit, props)
|
local function createTsObj(keyword, class, name, inherit, props)
|
||||||
local propsT = {}
|
local propsT = {}
|
||||||
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/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
|
||||||
|
|
||||||
@@ -801,7 +912,7 @@ 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/datablock: failed to create object', 3) end
|
error('bl.new/bl.datablock: failed to create object', 3) end
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
@@ -824,7 +935,7 @@ local function parseTsDecl(decl)
|
|||||||
isValidFuncName(class) and
|
isValidFuncName(class) and
|
||||||
(name==nil or isValidFuncName(name)) and
|
(name==nil or isValidFuncName(name)) and
|
||||||
(inherit==nil or isValidFuncName(inherit)) ) then
|
(inherit==nil or isValidFuncName(inherit)) ) then
|
||||||
error('bl.new/datablock: invalid decl \''..decl..'\'\n'..
|
error('bl.new/bl.datablock: invalid decl \''..decl..'\'\n'..
|
||||||
'must be of the format: \'className\', \'className name\', '..
|
'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
|
||||||
@@ -835,6 +946,7 @@ function bl.new(decl, 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
|
||||||
return createTsObj('datablock', class, name, inherit, props)
|
return createTsObj('datablock', class, name, inherit, props)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -121,13 +121,13 @@ function io.open(fn, mode, errn)
|
|||||||
local relfn = curfn and fn:find('^%./') and
|
local relfn = curfn and fn:find('^%./') and
|
||||||
curfn:gsub('[^/]+$', '')..fn:gsub('^%./', '')
|
curfn:gsub('[^/]+$', '')..fn:gsub('^%./', '')
|
||||||
if relfn then
|
if relfn then
|
||||||
local fi, err = io_open_absolute(relfn, mode, errn+1) -- defined with 2 args? function io_open_absolute(fn, mode)
|
local fi, err = io_open_absolute(relfn, mode)
|
||||||
return fi, err, relfn
|
return fi, err, relfn
|
||||||
else
|
else
|
||||||
return nil, 'Invalid path', fn
|
return nil, 'Invalid path', fn
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local fi, err = io_open_absolute(fn, mode, errn+1) -- defined with 2 args but passed 3 in.
|
local fi, err = io_open_absolute(fn, mode)
|
||||||
return fi, err, fn
|
return fi, err, fn
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -224,4 +224,8 @@ function _bllua_smarteval(code)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_bllua_ts.call('echo', ' Executed libts.lua')
|
function ts.setvar(name, val)
|
||||||
|
_bllua_ts.call('_bllua_set_var', name, val)
|
||||||
|
end
|
||||||
|
|
||||||
|
_bllua_ts.call('echo', ' Executed libts-lua.lua')
|
||||||
@@ -49,4 +49,26 @@ function _bllua_set_var(%name, %val) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo(" Executed libts-support.cs");
|
// Public Lua library for TS
|
||||||
|
function luacall(%func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_call", %func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p);
|
||||||
|
}
|
||||||
|
function luaexec(%fn) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_exec", %fn);
|
||||||
|
}
|
||||||
|
function luaeval(%code) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_eval", %code);
|
||||||
|
}
|
||||||
|
function luaget(%name) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_getvar", %name);
|
||||||
|
}
|
||||||
|
function luaset(%name, %val) {
|
||||||
|
if($_bllua_active)
|
||||||
|
_bllua_luacall("_bllua_setvar", %name, %val);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo(" Executed libts-ts.cs");
|
||||||
@@ -5,8 +5,7 @@
|
|||||||
-- Table / List
|
-- Table / List
|
||||||
-- Whether a table contains no keys
|
-- Whether a table contains no keys
|
||||||
function table.empty(t)
|
function table.empty(t)
|
||||||
for _,_ in pairs(t) do return false end
|
return next(t)~=nil
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
-- Apply a function to each key in a table
|
-- Apply a function to each key in a table
|
||||||
function table.map(f, ...)
|
function table.map(f, ...)
|
||||||
@@ -41,18 +40,6 @@ function table.reverse(l)
|
|||||||
for i=1,#l do m[#l-i+1] = l[i] end
|
for i=1,#l do m[#l-i+1] = l[i] end
|
||||||
return m
|
return m
|
||||||
end
|
end
|
||||||
-- Convert i->v to v->true
|
|
||||||
function table.values(l)
|
|
||||||
local u = {}
|
|
||||||
for _,v in ipairs(l) do u[v] = true end
|
|
||||||
return u
|
|
||||||
end
|
|
||||||
-- Make a list of keys
|
|
||||||
function table.keys(t)
|
|
||||||
local u = {}
|
|
||||||
for k,_ in pairs(t) do table.insert(u, k) end
|
|
||||||
return u
|
|
||||||
end
|
|
||||||
-- Whether a table is a list/array (has only monotonic integer keys)
|
-- Whether a table is a list/array (has only monotonic integer keys)
|
||||||
function table.islist(t)
|
function table.islist(t)
|
||||||
local n = 0
|
local n = 0
|
||||||
@@ -244,8 +231,8 @@ function string.bytes(s)
|
|||||||
end
|
end
|
||||||
-- Trim leading and trailing whitespace
|
-- Trim leading and trailing whitespace
|
||||||
function string.trim(s, ws)
|
function string.trim(s, ws)
|
||||||
ws = ws or '[ \t\r\t]'
|
ws = ws or ' \t\r\n'
|
||||||
return s:gsub('^'..ws..'+', ''):gsub(ws..'+$', '')..''
|
return s:gsub('^['..ws..']+', ''):gsub('['..ws..']+$', '')..''
|
||||||
end
|
end
|
||||||
-- String slicing and searching using [] operator
|
-- String slicing and searching using [] operator
|
||||||
local str_meta = getmetatable('')
|
local str_meta = getmetatable('')
|
||||||
@@ -325,7 +312,7 @@ end
|
|||||||
|
|
||||||
io = io or {}
|
io = io or {}
|
||||||
-- Read entire file at once, return nil,err if access failed
|
-- Read entire file at once, return nil,err if access failed
|
||||||
function io.readfile(filename)
|
function io.readall(filename)
|
||||||
local fi,err = io.open(filename, 'rb')
|
local fi,err = io.open(filename, 'rb')
|
||||||
if not fi then return nil,err end
|
if not fi then return nil,err end
|
||||||
local s = fi:read("*a")
|
local s = fi:read("*a")
|
||||||
@@ -333,7 +320,7 @@ function io.readfile(filename)
|
|||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
-- Write data to file all at once, return true if success / false,err if failure
|
-- Write data to file all at once, return true if success / false,err if failure
|
||||||
function io.writefile(filename, data)
|
function io.writeall(filename, data)
|
||||||
local fi,err = io.open(filename, 'wb')
|
local fi,err = io.open(filename, 'wb')
|
||||||
if not fi then return false,err end
|
if not fi then return false,err end
|
||||||
fi:write(data)
|
fi:write(data)
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ local vector_meta = {
|
|||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
table.insert(st, tostring(v1[i]))
|
table.insert(st, tostring(v1[i]))
|
||||||
end
|
end
|
||||||
return '{ '..table.concat(st, ', ')..' }'
|
return 'vector{ '..table.concat(st, ', ')..' }'
|
||||||
end,
|
end,
|
||||||
unpack = function(v1) return unpack(v1) end,
|
unpack = function(v1) return unpack(v1) end,
|
||||||
floor = vector_opn0n('floor', function(x1) return math.floor(x1) end),
|
floor = vector_opn0n('floor', function(x1) return math.floor(x1) end),
|
||||||
@@ -162,10 +162,10 @@ local vector_meta = {
|
|||||||
else error('vector rotateByAngleId: invalid rotation '..r, 2) end
|
else error('vector rotateByAngleId: invalid rotation '..r, 2) end
|
||||||
return v2
|
return v2
|
||||||
end,
|
end,
|
||||||
rotate2d = function(v, r)
|
rotateZ = function(v, r)
|
||||||
--vector_check(v, 2, 'rotate2d')
|
--vector_check(v, 2, 'rotate2d')
|
||||||
if type(r)~='number' then
|
if type(r)~='number' then
|
||||||
error('vector rotate2d: invalid rotation '..tostring(r), 2) end
|
error('vector rotateZ: invalid rotation '..tostring(r), 2) end
|
||||||
local len = math.sqrt(v[1]^2 + v[2]^2)
|
local len = math.sqrt(v[1]^2 + v[2]^2)
|
||||||
local ang = math.atan2(v[2], v[1]) + r
|
local ang = math.atan2(v[2], v[1]) + r
|
||||||
local v2 = vector_new{ math.cos(ang)*len, math.sin(ang)*len }
|
local v2 = vector_new{ math.cos(ang)*len, math.sin(ang)*len }
|
||||||
|
|||||||
Reference in New Issue
Block a user