1
0
forked from redo/BlockLua

Compare commits

...

20 Commits

Author SHA1 Message Date
b328f0b21a Merge branch 'master' 2025-12-09 15:43:41 -05:00
71b73c816b ... 2025-12-08 15:29:41 -05:00
c5dc8b15f9 Delete BlockLua.dll 2025-12-08 15:26:53 -05:00
Redo
8399b11322 fix table.empty, from auios 2025-12-08 11:49:23 -05:00
d494f02fe3 fix table.empty being inverted 2025-12-08 03:32:56 -05:00
a7db0d8e81 Update lua-env.lua 2025-12-08 03:32:31 -05:00
33f5ec9bbe Ensure fn is a string path 2025-12-08 03:32:12 -05:00
f6bf18efaa Fix md formatting + remove trailing whitespace 2025-12-08 03:30:54 -05:00
4f42801da6 Update compiling.md 2025-12-08 03:22:47 -05:00
15f67e0eef Fix invalid escape sequence for 5.1 2025-12-08 03:12:03 -05:00
5885dcbed3 Update libbl.lua 2025-12-08 03:09:47 -05:00
d9a416f5d5 Merge branch 'master' 2025-12-08 03:09:44 -05:00
Redo
2191e004ad recompile 2025-12-07 12:02:56 -05:00
Redo
ae34bb8b7a fix commandToClient, handle net strings when passed to lua, misc readme additions 2025-12-07 11:52:40 -05:00
Redo
b71bfdb73e support more+empty args in hooks 2025-10-13 12:28:16 -05:00
Redo
7232ede09d make :members() not return index, add -DBLLUA_ALLOWFFI, allow reading modules/lualib/, bug fixes 2025-10-06 23:03:12 -05:00
ed5c254480 .clang-format updates 2025-10-06 17:00:12 -04:00
5718ba8e6b Merge branch 'master' 2025-10-06 13:16:24 -04:00
a4f78b7425 Merge branch 'master' 2025-10-06 13:11:57 -04:00
Redo
76c758a47b allow luaget/luaset/luacall to access tables and methods, improve type conversion, add bl.string, begin adding matrix 2025-10-06 10:30:25 -05:00
29 changed files with 1198 additions and 1002 deletions

View File

@@ -1,4 +1,6 @@
BasedOnStyle: LLVM
# Include sorting and grouping
SortIncludes: CaseSensitive
IncludeBlocks: Preserve
IncludeCategories:
@@ -12,3 +14,29 @@ IncludeCategories:
Priority: 4
- Regex: ".*"
Priority: 5
# Indentation settings
IndentWidth: 2
UseTab: Never
IndentAccessModifiers: false
AccessModifierOffset: 0
NamespaceIndentation: All
# Line breaking and wrapping
ColumnLimit: 120
BreakBeforeTernaryOperators: false
BreakBeforeBinaryOperators: None
AlwaysBreakAfterReturnType: None
AlwaysBreakAfterDefinitionReturnType: None
# Alignment
AlignOperands: DontAlign
AlignAfterOpenBracket: AlwaysBreak
PointerAlignment: Left
# Parameter formatting
BinPackParameters: false
AllowAllParametersOfDeclarationOnNextLine: false
# Code organization
SeparateDefinitionBlocks: Always

View File

@@ -5,13 +5,13 @@ project(BlockLua CXX)
# Export compile_commands.json for VSCode IntelliSense
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Output directories to mirror compile.bat's build folder
# Output directories to mirror build.bat's build folder
set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/build)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR})
# Global compile options to mirror compile.bat
# Global build options to mirror build.bat
add_compile_options(
-Wall
-Werror
@@ -27,14 +27,14 @@ include_directories(
${CMAKE_SOURCE_DIR}/inc/lua
)
# Link directories (for -L.) and libraries from compile.bat
# Link directories (for -L.) and libraries from build.bat
link_directories(
${CMAKE_SOURCE_DIR}
)
# Safe DLL
add_library(BlockLua SHARED src/bllua4.cpp)
# Ensure output name matches compile.bat
# Ensure output name matches build.bat
set_target_properties(BlockLua PROPERTIES OUTPUT_NAME "BlockLua")
# Linker flags and libraries
if(MSVC)

View File

@@ -1,7 +1,7 @@
@echo off
cd /d %~dp0
REM Ensure MinGW32 toolchain is first in PATH (matches compile.bat)
REM Ensure MinGW32 toolchain is first in PATH
set "PATH=C:\msys64\mingw32\bin;%PATH%"
REM Configure CMake (generate into build/)

View File

@@ -1,13 +0,0 @@
@echo off
cd /d %~dp0
set "PATH=C:\msys64\mingw32\bin;%PATH%"
if not exist build mkdir build
set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++
echo on
g++ src/bllua4.cpp %buildargs% -o build\BlockLua.dll
g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o build\BlockLua-Unsafe.dll
@echo off

View File

@@ -27,7 +27,7 @@ What these packages are for:
- Run the script:
```powershell
compile.bat
build.bat
```
What the script does:
@@ -48,5 +48,5 @@ You should see `architecture: i386` in the output.
### Notes
- Ensure you installed the i686 (32-bit) variants of the packages; x86_64 packages wont work for a 32-bit build.
- Ensure you installed the i686 (32-bit) variants of the packages; x86_64 packages won't work for a 32-bit build.
- If the linker cannot find `-llua5.1`, confirm `mingw-w64-i686-lua51` is installed and you are using the `mingw32` toolchain (not `x86_64`).

View File

@@ -16,76 +16,63 @@
#define LUA_ERRFILE (LUA_ERRERR + 1)
typedef struct luaL_Reg {
const char *name;
const char* name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void(luaL_openlib)(lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void(luaL_register)(lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int(luaL_getmetafield)(lua_State *L, int obj, const char *e);
LUALIB_API int(luaL_callmeta)(lua_State *L, int obj, const char *e);
LUALIB_API int(luaL_typerror)(lua_State *L, int narg, const char *tname);
LUALIB_API int(luaL_argerror)(lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring)(lua_State * L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring)(lua_State * L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number(luaL_checknumber)(lua_State *L, int numArg);
LUALIB_API lua_Number(luaL_optnumber)(lua_State *L, int nArg, lua_Number def);
LUALIB_API void(luaL_openlib)(lua_State* L, const char* libname, const luaL_Reg* l, int nup);
LUALIB_API void(luaL_register)(lua_State* L, const char* libname, const luaL_Reg* l);
LUALIB_API int(luaL_getmetafield)(lua_State* L, int obj, const char* e);
LUALIB_API int(luaL_callmeta)(lua_State* L, int obj, const char* e);
LUALIB_API int(luaL_typerror)(lua_State* L, int narg, const char* tname);
LUALIB_API int(luaL_argerror)(lua_State* L, int numarg, const char* extramsg);
LUALIB_API const char*(luaL_checklstring)(lua_State * L, int numArg, size_t* l);
LUALIB_API const char*(luaL_optlstring)(lua_State * L, int numArg, const char* def, size_t* l);
LUALIB_API lua_Number(luaL_checknumber)(lua_State* L, int numArg);
LUALIB_API lua_Number(luaL_optnumber)(lua_State* L, int nArg, lua_Number def);
LUALIB_API lua_Integer(luaL_checkinteger)(lua_State *L, int numArg);
LUALIB_API lua_Integer(luaL_optinteger)(lua_State *L, int nArg,
lua_Integer def);
LUALIB_API lua_Integer(luaL_checkinteger)(lua_State* L, int numArg);
LUALIB_API lua_Integer(luaL_optinteger)(lua_State* L, int nArg, lua_Integer def);
LUALIB_API void(luaL_checkstack)(lua_State *L, int sz, const char *msg);
LUALIB_API void(luaL_checktype)(lua_State *L, int narg, int t);
LUALIB_API void(luaL_checkany)(lua_State *L, int narg);
LUALIB_API void(luaL_checkstack)(lua_State* L, int sz, const char* msg);
LUALIB_API void(luaL_checktype)(lua_State* L, int narg, int t);
LUALIB_API void(luaL_checkany)(lua_State* L, int narg);
LUALIB_API int(luaL_newmetatable)(lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata)(lua_State * L, int ud, const char *tname);
LUALIB_API int(luaL_newmetatable)(lua_State* L, const char* tname);
LUALIB_API void*(luaL_checkudata)(lua_State * L, int ud, const char* tname);
LUALIB_API void(luaL_where)(lua_State *L, int lvl);
LUALIB_API int(luaL_error)(lua_State *L, const char *fmt, ...);
LUALIB_API void(luaL_where)(lua_State* L, int lvl);
LUALIB_API int(luaL_error)(lua_State* L, const char* fmt, ...);
LUALIB_API int(luaL_checkoption)(lua_State *L, int narg, const char *def,
const char *const lst[]);
LUALIB_API int(luaL_checkoption)(lua_State* L, int narg, const char* def, const char* const lst[]);
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int(luaL_ref)(lua_State *L, int t);
LUALIB_API void(luaL_unref)(lua_State *L, int t, int ref);
LUALIB_API int(luaL_ref)(lua_State* L, int t);
LUALIB_API void(luaL_unref)(lua_State* L, int t, int ref);
LUALIB_API int(luaL_loadfile)(lua_State *L, const char *filename);
LUALIB_API int(luaL_loadbuffer)(lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int(luaL_loadstring)(lua_State *L, const char *s);
LUALIB_API int(luaL_loadfile)(lua_State* L, const char* filename);
LUALIB_API int(luaL_loadbuffer)(lua_State* L, const char* buff, size_t sz, const char* name);
LUALIB_API int(luaL_loadstring)(lua_State* L, const char* s);
LUALIB_API lua_State *(luaL_newstate)(void);
LUALIB_API lua_State*(luaL_newstate)(void);
LUALIB_API const char *(luaL_gsub)(lua_State * L, const char *s, const char *p,
const char *r);
LUALIB_API const char*(luaL_gsub)(lua_State * L, const char* s, const char* p, const char* r);
LUALIB_API const char *(luaL_findtable)(lua_State * L, int idx,
const char *fname, int szhint);
LUALIB_API const char*(luaL_findtable)(lua_State * L, int idx, const char* fname, int szhint);
/* From Lua 5.2. */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
LUALIB_API int luaL_execresult(lua_State *L, int stat);
LUALIB_API int(luaL_loadfilex)(lua_State *L, const char *filename,
const char *mode);
LUALIB_API int(luaL_loadbufferx)(lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API void luaL_traceback(lua_State *L, lua_State *L1, const char *msg,
int level);
LUALIB_API void(luaL_setfuncs)(lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API void(luaL_pushmodule)(lua_State *L, const char *modname,
int sizehint);
LUALIB_API void *(luaL_testudata)(lua_State * L, int ud, const char *tname);
LUALIB_API void(luaL_setmetatable)(lua_State *L, const char *tname);
LUALIB_API int luaL_fileresult(lua_State* L, int stat, const char* fname);
LUALIB_API int luaL_execresult(lua_State* L, int stat);
LUALIB_API int(luaL_loadfilex)(lua_State* L, const char* filename, const char* mode);
LUALIB_API int(luaL_loadbufferx)(lua_State* L, const char* buff, size_t sz, const char* name, const char* mode);
LUALIB_API void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level);
LUALIB_API void(luaL_setfuncs)(lua_State* L, const luaL_Reg* l, int nup);
LUALIB_API void(luaL_pushmodule)(lua_State* L, const char* modname, int sizehint);
LUALIB_API void*(luaL_testudata)(lua_State * L, int ud, const char* tname);
LUALIB_API void(luaL_setmetatable)(lua_State* L, const char* tname);
/*
** ===============================================================
@@ -93,8 +80,7 @@ LUALIB_API void(luaL_setmetatable)(lua_State *L, const char *tname);
** ===============================================================
*/
#define luaL_argcheck(L, cond, numarg, extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_argcheck(L, cond, numarg, extramsg) ((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L, n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L, n, d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L, n) ((int)luaL_checkinteger(L, (n)))
@@ -104,19 +90,16 @@ LUALIB_API void(luaL_setmetatable)(lua_State *L, const char *tname);
#define luaL_typename(L, i) lua_typename(L, lua_type(L, (i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L, n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L, f, n, d) (lua_isnoneornil(L, (n)) ? (d) : f(L, (n)))
/* From Lua 5.2. */
#define luaL_newlibtable(L, l) \
lua_createtable(L, 0, sizeof(l) / sizeof((l)[0]) - 1)
#define luaL_newlibtable(L, l) lua_createtable(L, 0, sizeof(l) / sizeof((l)[0]) - 1)
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
/*
@@ -126,27 +109,26 @@ LUALIB_API void(luaL_setmetatable)(lua_State *L, const char *tname);
*/
typedef struct luaL_Buffer {
char *p; /* current position in buffer */
char* p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
lua_State* L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;
#define luaL_addchar(B, c) \
((void)((B)->p < ((B)->buffer + LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))
#define luaL_addchar(B, c) \
((void)((B)->p < ((B)->buffer + LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), (*(B)->p++ = (char)(c)))
/* compatibility only */
#define luaL_putchar(B, c) luaL_addchar(B, c)
#define luaL_addsize(B, n) ((B)->p += (n))
LUALIB_API void(luaL_buffinit)(lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer)(luaL_Buffer * B);
LUALIB_API void(luaL_addlstring)(luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void(luaL_addstring)(luaL_Buffer *B, const char *s);
LUALIB_API void(luaL_addvalue)(luaL_Buffer *B);
LUALIB_API void(luaL_pushresult)(luaL_Buffer *B);
LUALIB_API void(luaL_buffinit)(lua_State* L, luaL_Buffer* B);
LUALIB_API char*(luaL_prepbuffer)(luaL_Buffer * B);
LUALIB_API void(luaL_addlstring)(luaL_Buffer* B, const char* s, size_t l);
LUALIB_API void(luaL_addstring)(luaL_Buffer* B, const char* s);
LUALIB_API void(luaL_addvalue)(luaL_Buffer* B);
LUALIB_API void(luaL_pushresult)(luaL_Buffer* B);
/* }====================================================== */

View File

@@ -43,19 +43,19 @@
typedef struct lua_State lua_State;
typedef int (*lua_CFunction)(lua_State *L);
typedef int (*lua_CFunction)(lua_State* L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char *(*lua_Reader)(lua_State *L, void *ud, size_t *sz);
typedef const char* (*lua_Reader)(lua_State* L, void* ud, size_t* sz);
typedef int (*lua_Writer)(lua_State *L, const void *p, size_t sz, void *ud);
typedef int (*lua_Writer)(lua_State* L, const void* p, size_t sz, void* ud);
/*
** prototype for memory-allocation functions
*/
typedef void *(*lua_Alloc)(void *ud, void *ptr, size_t osize, size_t nsize);
typedef void* (*lua_Alloc)(void* ud, void* ptr, size_t osize, size_t nsize);
/*
** basic types
@@ -91,105 +91,103 @@ typedef LUA_INTEGER lua_Integer;
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate)(lua_Alloc f, void *ud);
LUA_API void(lua_close)(lua_State *L);
LUA_API lua_State *(lua_newthread)(lua_State * L);
LUA_API lua_State*(lua_newstate)(lua_Alloc f, void* ud);
LUA_API void(lua_close)(lua_State* L);
LUA_API lua_State*(lua_newthread)(lua_State * L);
LUA_API lua_CFunction(lua_atpanic)(lua_State *L, lua_CFunction panicf);
LUA_API lua_CFunction(lua_atpanic)(lua_State* L, lua_CFunction panicf);
/*
** basic stack manipulation
*/
LUA_API int(lua_gettop)(lua_State *L);
LUA_API void(lua_settop)(lua_State *L, int idx);
LUA_API void(lua_pushvalue)(lua_State *L, int idx);
LUA_API void(lua_remove)(lua_State *L, int idx);
LUA_API void(lua_insert)(lua_State *L, int idx);
LUA_API void(lua_replace)(lua_State *L, int idx);
LUA_API int(lua_checkstack)(lua_State *L, int sz);
LUA_API int(lua_gettop)(lua_State* L);
LUA_API void(lua_settop)(lua_State* L, int idx);
LUA_API void(lua_pushvalue)(lua_State* L, int idx);
LUA_API void(lua_remove)(lua_State* L, int idx);
LUA_API void(lua_insert)(lua_State* L, int idx);
LUA_API void(lua_replace)(lua_State* L, int idx);
LUA_API int(lua_checkstack)(lua_State* L, int sz);
LUA_API void(lua_xmove)(lua_State *from, lua_State *to, int n);
LUA_API void(lua_xmove)(lua_State* from, lua_State* to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int(lua_isnumber)(lua_State *L, int idx);
LUA_API int(lua_isstring)(lua_State *L, int idx);
LUA_API int(lua_iscfunction)(lua_State *L, int idx);
LUA_API int(lua_isuserdata)(lua_State *L, int idx);
LUA_API int(lua_type)(lua_State *L, int idx);
LUA_API const char *(lua_typename)(lua_State * L, int tp);
LUA_API int(lua_isnumber)(lua_State* L, int idx);
LUA_API int(lua_isstring)(lua_State* L, int idx);
LUA_API int(lua_iscfunction)(lua_State* L, int idx);
LUA_API int(lua_isuserdata)(lua_State* L, int idx);
LUA_API int(lua_type)(lua_State* L, int idx);
LUA_API const char*(lua_typename)(lua_State * L, int tp);
LUA_API int(lua_equal)(lua_State *L, int idx1, int idx2);
LUA_API int(lua_rawequal)(lua_State *L, int idx1, int idx2);
LUA_API int(lua_lessthan)(lua_State *L, int idx1, int idx2);
LUA_API int(lua_equal)(lua_State* L, int idx1, int idx2);
LUA_API int(lua_rawequal)(lua_State* L, int idx1, int idx2);
LUA_API int(lua_lessthan)(lua_State* L, int idx1, int idx2);
LUA_API lua_Number(lua_tonumber)(lua_State *L, int idx);
LUA_API lua_Integer(lua_tointeger)(lua_State *L, int idx);
LUA_API int(lua_toboolean)(lua_State *L, int idx);
LUA_API const char *(lua_tolstring)(lua_State * L, int idx, size_t *len);
LUA_API size_t(lua_objlen)(lua_State *L, int idx);
LUA_API lua_CFunction(lua_tocfunction)(lua_State *L, int idx);
LUA_API void *(lua_touserdata)(lua_State * L, int idx);
LUA_API lua_State *(lua_tothread)(lua_State * L, int idx);
LUA_API const void *(lua_topointer)(lua_State * L, int idx);
LUA_API lua_Number(lua_tonumber)(lua_State* L, int idx);
LUA_API lua_Integer(lua_tointeger)(lua_State* L, int idx);
LUA_API int(lua_toboolean)(lua_State* L, int idx);
LUA_API const char*(lua_tolstring)(lua_State * L, int idx, size_t* len);
LUA_API size_t(lua_objlen)(lua_State* L, int idx);
LUA_API lua_CFunction(lua_tocfunction)(lua_State* L, int idx);
LUA_API void*(lua_touserdata)(lua_State * L, int idx);
LUA_API lua_State*(lua_tothread)(lua_State * L, int idx);
LUA_API const void*(lua_topointer)(lua_State * L, int idx);
/*
** push functions (C -> stack)
*/
LUA_API void(lua_pushnil)(lua_State *L);
LUA_API void(lua_pushnumber)(lua_State *L, lua_Number n);
LUA_API void(lua_pushinteger)(lua_State *L, lua_Integer n);
LUA_API void(lua_pushlstring)(lua_State *L, const char *s, size_t l);
LUA_API void(lua_pushstring)(lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring)(lua_State * L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring)(lua_State * L, const char *fmt, ...);
LUA_API void(lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n);
LUA_API void(lua_pushboolean)(lua_State *L, int b);
LUA_API void(lua_pushlightuserdata)(lua_State *L, void *p);
LUA_API int(lua_pushthread)(lua_State *L);
LUA_API void(lua_pushnil)(lua_State* L);
LUA_API void(lua_pushnumber)(lua_State* L, lua_Number n);
LUA_API void(lua_pushinteger)(lua_State* L, lua_Integer n);
LUA_API void(lua_pushlstring)(lua_State* L, const char* s, size_t l);
LUA_API void(lua_pushstring)(lua_State* L, const char* s);
LUA_API const char*(lua_pushvfstring)(lua_State * L, const char* fmt, va_list argp);
LUA_API const char*(lua_pushfstring)(lua_State * L, const char* fmt, ...);
LUA_API void(lua_pushcclosure)(lua_State* L, lua_CFunction fn, int n);
LUA_API void(lua_pushboolean)(lua_State* L, int b);
LUA_API void(lua_pushlightuserdata)(lua_State* L, void* p);
LUA_API int(lua_pushthread)(lua_State* L);
/*
** get functions (Lua -> stack)
*/
LUA_API void(lua_gettable)(lua_State *L, int idx);
LUA_API void(lua_getfield)(lua_State *L, int idx, const char *k);
LUA_API void(lua_rawget)(lua_State *L, int idx);
LUA_API void(lua_rawgeti)(lua_State *L, int idx, int n);
LUA_API void(lua_createtable)(lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata)(lua_State * L, size_t sz);
LUA_API int(lua_getmetatable)(lua_State *L, int objindex);
LUA_API void(lua_getfenv)(lua_State *L, int idx);
LUA_API void(lua_gettable)(lua_State* L, int idx);
LUA_API void(lua_getfield)(lua_State* L, int idx, const char* k);
LUA_API void(lua_rawget)(lua_State* L, int idx);
LUA_API void(lua_rawgeti)(lua_State* L, int idx, int n);
LUA_API void(lua_createtable)(lua_State* L, int narr, int nrec);
LUA_API void*(lua_newuserdata)(lua_State * L, size_t sz);
LUA_API int(lua_getmetatable)(lua_State* L, int objindex);
LUA_API void(lua_getfenv)(lua_State* L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void(lua_settable)(lua_State *L, int idx);
LUA_API void(lua_setfield)(lua_State *L, int idx, const char *k);
LUA_API void(lua_rawset)(lua_State *L, int idx);
LUA_API void(lua_rawseti)(lua_State *L, int idx, int n);
LUA_API int(lua_setmetatable)(lua_State *L, int objindex);
LUA_API int(lua_setfenv)(lua_State *L, int idx);
LUA_API void(lua_settable)(lua_State* L, int idx);
LUA_API void(lua_setfield)(lua_State* L, int idx, const char* k);
LUA_API void(lua_rawset)(lua_State* L, int idx);
LUA_API void(lua_rawseti)(lua_State* L, int idx, int n);
LUA_API int(lua_setmetatable)(lua_State* L, int objindex);
LUA_API int(lua_setfenv)(lua_State* L, int idx);
/*
** `load' and `call' functions (load and run Lua code)
*/
LUA_API void(lua_call)(lua_State *L, int nargs, int nresults);
LUA_API int(lua_pcall)(lua_State *L, int nargs, int nresults, int errfunc);
LUA_API int(lua_cpcall)(lua_State *L, lua_CFunction func, void *ud);
LUA_API int(lua_load)(lua_State *L, lua_Reader reader, void *dt,
const char *chunkname);
LUA_API void(lua_call)(lua_State* L, int nargs, int nresults);
LUA_API int(lua_pcall)(lua_State* L, int nargs, int nresults, int errfunc);
LUA_API int(lua_cpcall)(lua_State* L, lua_CFunction func, void* ud);
LUA_API int(lua_load)(lua_State* L, lua_Reader reader, void* dt, const char* chunkname);
LUA_API int(lua_dump)(lua_State *L, lua_Writer writer, void *data);
LUA_API int(lua_dump)(lua_State* L, lua_Writer writer, void* data);
/*
** coroutine functions
*/
LUA_API int(lua_yield)(lua_State *L, int nresults);
LUA_API int(lua_resume)(lua_State *L, int narg);
LUA_API int(lua_status)(lua_State *L);
LUA_API int(lua_yield)(lua_State* L, int nresults);
LUA_API int(lua_resume)(lua_State* L, int narg);
LUA_API int(lua_status)(lua_State* L);
/*
** garbage-collection function and options
@@ -205,20 +203,20 @@ LUA_API int(lua_status)(lua_State *L);
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
LUA_API int(lua_gc)(lua_State *L, int what, int data);
LUA_API int(lua_gc)(lua_State* L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int(lua_error)(lua_State *L);
LUA_API int(lua_error)(lua_State* L);
LUA_API int(lua_next)(lua_State *L, int idx);
LUA_API int(lua_next)(lua_State* L, int idx);
LUA_API void(lua_concat)(lua_State *L, int n);
LUA_API void(lua_concat)(lua_State* L, int n);
LUA_API lua_Alloc(lua_getallocf)(lua_State *L, void **ud);
LUA_API void lua_setallocf(lua_State *L, lua_Alloc f, void *ud);
LUA_API lua_Alloc(lua_getallocf)(lua_State* L, void** ud);
LUA_API void lua_setallocf(lua_State* L, lua_Alloc f, void* ud);
/*
** ===============================================================
@@ -245,8 +243,7 @@ LUA_API void lua_setallocf(lua_State *L, lua_Alloc f, void *ud);
#define lua_isnone(L, n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s) / sizeof(char)) - 1)
#define lua_pushliteral(L, s) lua_pushlstring(L, "" s, (sizeof(s) / sizeof(char)) - 1)
#define lua_setglobal(L, s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
#define lua_getglobal(L, s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
@@ -267,7 +264,7 @@ LUA_API void lua_setallocf(lua_State *L, lua_Alloc f, void *ud);
#define lua_Chunkwriter lua_Writer
/* hack */
LUA_API void lua_setlevel(lua_State *from, lua_State *to);
LUA_API void lua_setlevel(lua_State* from, lua_State* to);
/*
** {======================================================================
@@ -295,38 +292,37 @@ LUA_API void lua_setlevel(lua_State *from, lua_State *to);
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debuger in specific events */
typedef void (*lua_Hook)(lua_State *L, lua_Debug *ar);
typedef void (*lua_Hook)(lua_State* L, lua_Debug* ar);
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar);
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_getupvalue(lua_State *L, int funcindex, int n);
LUA_API const char *lua_setupvalue(lua_State *L, int funcindex, int n);
LUA_API int lua_sethook(lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook lua_gethook(lua_State *L);
LUA_API int lua_gethookmask(lua_State *L);
LUA_API int lua_gethookcount(lua_State *L);
LUA_API int lua_getstack(lua_State* L, int level, lua_Debug* ar);
LUA_API int lua_getinfo(lua_State* L, const char* what, lua_Debug* ar);
LUA_API const char* lua_getlocal(lua_State* L, const lua_Debug* ar, int n);
LUA_API const char* lua_setlocal(lua_State* L, const lua_Debug* ar, int n);
LUA_API const char* lua_getupvalue(lua_State* L, int funcindex, int n);
LUA_API const char* lua_setupvalue(lua_State* L, int funcindex, int n);
LUA_API int lua_sethook(lua_State* L, lua_Hook func, int mask, int count);
LUA_API lua_Hook lua_gethook(lua_State* L);
LUA_API int lua_gethookmask(lua_State* L);
LUA_API int lua_gethookcount(lua_State* L);
/* From Lua 5.2. */
LUA_API void *lua_upvalueid(lua_State *L, int idx, int n);
LUA_API void lua_upvaluejoin(lua_State *L, int idx1, int n1, int idx2, int n2);
LUA_API int lua_loadx(lua_State *L, lua_Reader reader, void *dt,
const char *chunkname, const char *mode);
LUA_API const lua_Number *lua_version(lua_State *L);
LUA_API void lua_copy(lua_State *L, int fromidx, int toidx);
LUA_API lua_Number lua_tonumberx(lua_State *L, int idx, int *isnum);
LUA_API lua_Integer lua_tointegerx(lua_State *L, int idx, int *isnum);
LUA_API void* lua_upvalueid(lua_State* L, int idx, int n);
LUA_API void lua_upvaluejoin(lua_State* L, int idx1, int n1, int idx2, int n2);
LUA_API int lua_loadx(lua_State* L, lua_Reader reader, void* dt, const char* chunkname, const char* mode);
LUA_API const lua_Number* lua_version(lua_State* L);
LUA_API void lua_copy(lua_State* L, int fromidx, int toidx);
LUA_API lua_Number lua_tonumberx(lua_State* L, int idx, int* isnum);
LUA_API lua_Integer lua_tointegerx(lua_State* L, int idx, int* isnum);
/* From Lua 5.3. */
LUA_API int lua_isyieldable(lua_State *L);
LUA_API int lua_isyieldable(lua_State* L);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) `global', `local', `field', `method' */
const char *what; /* (S) `Lua', `C', `main', `tail' */
const char *source; /* (S) */
const char* name; /* (n) */
const char* namewhat; /* (n) `global', `local', `field', `method' */
const char* what; /* (S) `Lua', `C', `main', `tail' */
const char* source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) number of upvalues */
int linedefined; /* (S) */

View File

@@ -9,6 +9,7 @@
#ifndef WINVER
#define WINVER 0x0501
#endif
#include <limits.h>
#include <stddef.h>
@@ -75,9 +76,7 @@
#define LUA_PATH_MARK "?"
#define LUA_EXECDIR "!"
#define LUA_IGMARK "-"
#define LUA_PATH_CONFIG \
LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" LUA_EXECDIR \
"\n" LUA_IGMARK "\n"
#define LUA_PATH_CONFIG LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" LUA_EXECDIR "\n" LUA_IGMARK "\n"
/* Quoting in error messages. */
#define LUA_QL(x) "'" x "'"
@@ -142,15 +141,15 @@
#define lua_assert(x) assert(x)
#endif
#ifdef LUA_USE_APICHECK
#define luai_apicheck(L, o) \
{ \
(void)L; \
assert(o); \
#define luai_apicheck(L, o) \
{ \
(void)L; \
assert(o); \
}
#else
#define luai_apicheck(L, o) \
{ \
(void)L; \
#define luai_apicheck(L, o) \
{ \
(void)L; \
}
#endif

View File

@@ -62,16 +62,13 @@ enum {
/* LuaJIT public C API. */
/* Control the JIT engine. */
LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
LUA_API int luaJIT_setmode(lua_State* L, int idx, int mode);
/* Low-overhead profiling API. */
typedef void (*luaJIT_profile_callback)(void *data, lua_State *L, int samples,
int vmstate);
LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
luaJIT_profile_callback cb, void *data);
LUA_API void luaJIT_profile_stop(lua_State *L);
LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
int depth, size_t *len);
typedef void (*luaJIT_profile_callback)(void* data, lua_State* L, int samples, int vmstate);
LUA_API void luaJIT_profile_start(lua_State* L, const char* mode, luaJIT_profile_callback cb, void* data);
LUA_API void luaJIT_profile_stop(lua_State* L);
LUA_API const char* luaJIT_profile_dumpstack(lua_State* L, const char* fmt, int depth, size_t* len);
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
LUA_API void LUAJIT_VERSION_SYM(void);

View File

@@ -22,19 +22,19 @@
#define LUA_JITLIBNAME "jit"
#define LUA_FFILIBNAME "ffi"
LUALIB_API int luaopen_base(lua_State *L);
LUALIB_API int luaopen_math(lua_State *L);
LUALIB_API int luaopen_string(lua_State *L);
LUALIB_API int luaopen_table(lua_State *L);
LUALIB_API int luaopen_io(lua_State *L);
LUALIB_API int luaopen_os(lua_State *L);
LUALIB_API int luaopen_package(lua_State *L);
LUALIB_API int luaopen_debug(lua_State *L);
LUALIB_API int luaopen_bit(lua_State *L);
LUALIB_API int luaopen_jit(lua_State *L);
LUALIB_API int luaopen_ffi(lua_State *L);
LUALIB_API int luaopen_base(lua_State* L);
LUALIB_API int luaopen_math(lua_State* L);
LUALIB_API int luaopen_string(lua_State* L);
LUALIB_API int luaopen_table(lua_State* L);
LUALIB_API int luaopen_io(lua_State* L);
LUALIB_API int luaopen_os(lua_State* L);
LUALIB_API int luaopen_package(lua_State* L);
LUALIB_API int luaopen_debug(lua_State* L);
LUALIB_API int luaopen_bit(lua_State* L);
LUALIB_API int luaopen_jit(lua_State* L);
LUALIB_API int luaopen_ffi(lua_State* L);
LUALIB_API void luaL_openlibs(lua_State *L);
LUALIB_API void luaL_openlibs(lua_State* L);
#ifndef lua_assert
#define lua_assert(x) ((void)0)

View File

@@ -38,52 +38,53 @@ BlFunctionDefIntern(tsf_BlCon__getReturnBuffer);
// C->TS Args
char *tsf_GetIntArg(signed int value) {
char *ret = tsf_BlStringStack__getArgBuffer(16);
char* tsf_GetIntArg(signed int value) {
char* ret = tsf_BlStringStack__getArgBuffer(16);
snprintf(ret, 16, "%d", value);
return ret;
}
char *tsf_GetFloatArg(float value) {
char *ret = tsf_BlStringStack__getArgBuffer(32);
char* tsf_GetFloatArg(float value) {
char* ret = tsf_BlStringStack__getArgBuffer(32);
snprintf(ret, 32, "%g", value);
return ret;
}
char *tsf_GetStringArg(char *value) {
char* tsf_GetStringArg(char* value) {
int len = strlen(value) + 1;
char *ret = tsf_BlStringStack__getArgBuffer(len);
char* ret = tsf_BlStringStack__getArgBuffer(len);
memcpy(ret, value, len);
return ret;
}
char *tsf_GetThisArg(ADDR obj) {
return tsf_GetIntArg(*(signed int *)(obj + 32));
}
char* tsf_GetThisArg(ADDR obj) { return tsf_GetIntArg(*(signed int*)(obj + 32)); }
// Eval
const char *tsf_Eval(const char *code) {
const char *argv[] = {nullptr, code};
const char* tsf_Eval(const char* code) {
const char* argv[] = {nullptr, code};
return tsf_BlCon__evaluate(0, 2, argv);
}
const char *tsf_Evalf(const char *fmt, ...) {
const char* tsf_Evalf(const char* fmt, ...) {
va_list args;
char code[4096];
va_start(args, fmt);
vsnprintf(code, 4096, fmt, args);
va_end(args);
return tsf_Eval((const char *)code);
return tsf_Eval((const char*)code);
}
// Objects
ADDR tsf_FindObject(unsigned int id) {
ADDR obj = *(ADDR *)(*(ADDR *)(tsf_gIdDictionary) + 4 * (id & 0xFFF));
ADDR obj = *(ADDR*)(*(ADDR*)(tsf_gIdDictionary) + 4 * (id & 0xFFF));
if (!obj)
return 0;
while (obj && *(unsigned int *)(obj + 32) != id) {
obj = *(ADDR *)(obj + 16);
while (obj && *(unsigned int*)(obj + 32) != id) {
obj = *(ADDR*)(obj + 16);
if (!obj)
return 0;
}
@@ -91,12 +92,10 @@ ADDR tsf_FindObject(unsigned int id) {
return obj;
}
ADDR tsf_FindObject(const char *name) {
return (ADDR)tsf_BlSim__findObject_name(name);
}
ADDR tsf_FindObject(const char* name) { return (ADDR)tsf_BlSim__findObject_name(name); }
ADDR tsf_LookupNamespace(const char *ns, const char *package) {
const char *ste_package;
ADDR tsf_LookupNamespace(const char* ns, const char* package) {
const char* ste_package;
if (package) {
ste_package = tsf_BlStringTable__insert(package, 0);
} else {
@@ -104,21 +103,19 @@ ADDR tsf_LookupNamespace(const char *ns, const char *package) {
}
if (ns) {
const char *ste_namespace = tsf_BlStringTable__insert(ns, 0);
const char* ste_namespace = tsf_BlStringTable__insert(ns, 0);
return tsf_BlNamespace__find(ste_namespace, ste_package);
} else {
return tsf_BlNamespace__find(nullptr, ste_package);
}
}
ADDR tsf_LookupNamespace(const char *ns) {
return tsf_LookupNamespace(ns, nullptr);
}
ADDR tsf_LookupNamespace(const char* ns) { return tsf_LookupNamespace(ns, nullptr); }
// Object Fields
const char *tsf_GetDataField(ADDR simObject, const char *slotName,
const char *array) {
const char *ste_slotName;
const char* tsf_GetDataField(ADDR simObject, const char* slotName, const char* array) {
const char* ste_slotName;
if (slotName) {
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
} else {
@@ -128,9 +125,8 @@ const char *tsf_GetDataField(ADDR simObject, const char *slotName,
return tsf_BlSimObject__getDataField(simObject, ste_slotName, array);
}
void tsf_SetDataField(ADDR simObject, const char *slotName, const char *array,
const char *value) {
const char *ste_slotName;
void tsf_SetDataField(ADDR simObject, const char* slotName, const char* array, const char* value) {
const char* ste_slotName;
if (slotName) {
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
} else {
@@ -142,83 +138,103 @@ void tsf_SetDataField(ADDR simObject, const char *slotName, const char *array,
// TS Global Variables
const char *tsf_GetVar(const char *name) {
return tsf_BlCon__getVariable(name);
const char* tsf_GetVar(const char* name) { return tsf_BlCon__getVariable(name); }
void tsf_AddVarInternal(const char* name, signed int varType, void* data) {
tsf_BlDictionary__addVariable((ADDR*)tsf_gEvalState_globalVars, name, varType, data);
}
void tsf_AddVarInternal(const char *name, signed int varType, void *data) {
tsf_BlDictionary__addVariable((ADDR *)tsf_gEvalState_globalVars, name,
varType, data);
}
void tsf_AddVar(const char* name, const char** data) { tsf_AddVarInternal(name, 10, data); }
void tsf_AddVar(const char *name, const char **data) {
tsf_AddVarInternal(name, 10, data);
}
void tsf_AddVar(const char *name, signed int *data) {
tsf_AddVarInternal(name, 4, data);
}
void tsf_AddVar(const char *name, float *data) {
tsf_AddVarInternal(name, 8, data);
}
void tsf_AddVar(const char *name, bool *data) {
tsf_AddVarInternal(name, 6, data);
}
void tsf_AddVar(const char* name, signed int* data) { tsf_AddVarInternal(name, 4, data); }
void tsf_AddVar(const char* name, float* data) { tsf_AddVarInternal(name, 8, data); }
void tsf_AddVar(const char* name, bool* data) { tsf_AddVarInternal(name, 6, data); }
// TS->C Functions
ADDR tsf_AddConsoleFuncInternal(const char *pname, const char *cname,
const char *fname, signed int cbtype,
const char *usage, signed int mina,
signed int maxa) {
const char *ste_fname = tsf_BlStringTable__insert(fname, 0);
ADDR tsf_AddConsoleFuncInternal(
const char* pname,
const char* cname,
const char* fname,
signed int cbtype,
const char* usage,
signed int mina,
signed int maxa) {
const char* ste_fname = tsf_BlStringTable__insert(fname, 0);
ADDR ns = tsf_LookupNamespace(cname, pname);
ADDR ent = tsf_BlNamespace__createLocalEntry(ns, ste_fname);
*(signed int *)tsf_mCacheSequence += 1;
tsf_BlDataChunker__freeBlocks(*(ADDR *)tsf_mCacheAllocator);
*(signed int*)tsf_mCacheSequence += 1;
tsf_BlDataChunker__freeBlocks(*(ADDR*)tsf_mCacheAllocator);
*(const char **)(ent + 24) = usage;
*(signed int *)(ent + 16) = mina;
*(signed int *)(ent + 20) = maxa;
*(signed int *)(ent + 12) = cbtype;
*(const char**)(ent + 24) = usage;
*(signed int*)(ent + 16) = mina;
*(signed int*)(ent + 20) = maxa;
*(signed int*)(ent + 12) = cbtype;
return ent;
}
void tsf_AddConsoleFunc(const char *pname, const char *cname, const char *fname,
tsf_StringCallback sc, const char *usage,
signed int mina, signed int maxa) {
ADDR ent =
tsf_AddConsoleFuncInternal(pname, cname, fname, 1, usage, mina, maxa);
*(tsf_StringCallback *)(ent + 40) = sc;
void tsf_AddConsoleFunc(
const char* pname,
const char* cname,
const char* fname,
tsf_StringCallback sc,
const char* usage,
signed int mina,
signed int maxa) {
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 1, usage, mina, maxa);
*(tsf_StringCallback*)(ent + 40) = sc;
}
void tsf_AddConsoleFunc(const char *pname, const char *cname, const char *fname,
tsf_IntCallback ic, const char *usage, signed int mina,
signed int maxa) {
ADDR ent =
tsf_AddConsoleFuncInternal(pname, cname, fname, 2, usage, mina, maxa);
*(tsf_IntCallback *)(ent + 40) = ic;
void tsf_AddConsoleFunc(
const char* pname,
const char* cname,
const char* fname,
tsf_IntCallback ic,
const char* usage,
signed int mina,
signed int maxa) {
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 2, usage, mina, maxa);
*(tsf_IntCallback*)(ent + 40) = ic;
}
void tsf_AddConsoleFunc(const char *pname, const char *cname, const char *fname,
tsf_FloatCallback fc, const char *usage,
signed int mina, signed int maxa) {
ADDR ent =
tsf_AddConsoleFuncInternal(pname, cname, fname, 3, usage, mina, maxa);
*(tsf_FloatCallback *)(ent + 40) = fc;
void tsf_AddConsoleFunc(
const char* pname,
const char* cname,
const char* fname,
tsf_FloatCallback fc,
const char* usage,
signed int mina,
signed int maxa) {
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 3, usage, mina, maxa);
*(tsf_FloatCallback*)(ent + 40) = fc;
}
void tsf_AddConsoleFunc(const char *pname, const char *cname, const char *fname,
tsf_VoidCallback vc, const char *usage, signed int mina,
signed int maxa) {
ADDR ent =
tsf_AddConsoleFuncInternal(pname, cname, fname, 4, usage, mina, maxa);
*(tsf_VoidCallback *)(ent + 40) = vc;
void tsf_AddConsoleFunc(
const char* pname,
const char* cname,
const char* fname,
tsf_VoidCallback vc,
const char* usage,
signed int mina,
signed int maxa) {
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 4, usage, mina, maxa);
*(tsf_VoidCallback*)(ent + 40) = vc;
}
void tsf_AddConsoleFunc(const char *pname, const char *cname, const char *fname,
tsf_BoolCallback bc, const char *usage, signed int mina,
signed int maxa) {
ADDR ent =
tsf_AddConsoleFuncInternal(pname, cname, fname, 5, usage, mina, maxa);
*(tsf_BoolCallback *)(ent + 40) = bc;
void tsf_AddConsoleFunc(
const char* pname,
const char* cname,
const char* fname,
tsf_BoolCallback bc,
const char* usage,
signed int mina,
signed int maxa) {
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 5, usage, mina, maxa);
*(tsf_BoolCallback*)(ent + 40) = bc;
}
// Initialization
@@ -233,49 +249,54 @@ bool tsf_InitInternal() {
tsf_BlNamespace__createLocalEntry,
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 08 53 56 57 A1 ? ? ? ? "
"33 C5 50 8D 45 F4 64 A3 ? ? ? ? 89 4D F0");
BlScanFunctionText(tsf_BlDataChunker__freeBlocks,
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 51 53 56 57 "
"A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B D9 8B 33");
BlScanFunctionText(tsf_BlCon__evaluate,
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 56 57 A1 ? ? "
"? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B 75 10");
BlScanFunctionText(tsf_BlCon__executef,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 55 56 "
"8B B4 24 ? ? ? ? 33 C9");
BlScanFunctionText(tsf_BlCon__executefSimObj,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 56 8B "
"B4 24 ? ? ? ? 33 C9");
BlScanFunctionText(tsf_BlCon__getVariable,
"53 56 8B F1 57 85 F6 0F 84 ? ? ? ?");
BlScanFunctionText(
tsf_BlDataChunker__freeBlocks,
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 51 53 56 57 "
"A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B D9 8B 33");
BlScanFunctionText(
tsf_BlCon__evaluate,
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 56 57 A1 ? ? "
"? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B 75 10");
BlScanFunctionText(
tsf_BlCon__executef,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 55 56 "
"8B B4 24 ? ? ? ? 33 C9");
BlScanFunctionText(
tsf_BlCon__executefSimObj,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 56 8B "
"B4 24 ? ? ? ? 33 C9");
BlScanFunctionText(tsf_BlCon__getVariable, "53 56 8B F1 57 85 F6 0F 84 ? ? ? ?");
BlScanFunctionText(tsf_BlDictionary__addVariable, "8B 44 24 04 56 57 8B F9");
BlScanFunctionText(tsf_BlSim__findObject_name, "57 8B F9 8A 17");
BlScanFunctionText(tsf_BlStringStack__getArgBuffer,
"55 8B EC 83 E4 F8 8B 0D ? ? ? ? A1 ? ? ? ? 56 57 8B 7D "
"08 8D 14 01 03 D7 3B 15 ? ? ? ? 72 2C 8B 0D");
BlScanFunctionText(tsf_BlSimObject__getDataField,
"51 53 8B D9 55 56 8B 74 24 14");
BlScanFunctionText(tsf_BlSimObject__setDataField,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 8B 84 24 "
"? ? ? ? 53 8B D9 89 44 24 04");
BlScanFunctionText(
tsf_BlStringStack__getArgBuffer,
"55 8B EC 83 E4 F8 8B 0D ? ? ? ? A1 ? ? ? ? 56 57 8B 7D "
"08 8D 14 01 03 D7 3B 15 ? ? ? ? 72 2C 8B 0D");
BlScanFunctionText(tsf_BlSimObject__getDataField, "51 53 8B D9 55 56 8B 74 24 14");
BlScanFunctionText(
tsf_BlSimObject__setDataField,
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 8B 84 24 "
"? ? ? ? 53 8B D9 89 44 24 04");
BlScanFunctionText(tsf_BlCon__getReturnBuffer, "81 F9 ? ? ? ? 76 2B");
ADDR BlScanText(tsf_mCacheSequenceLoc,
"FF 05 ? ? ? ? B9 ? ? ? ? 8B F8 E8 ? ? ? ? 8B 44 24 1C 89 47 "
"18 8B 44 24 14");
ADDR BlScanText(
tsf_mCacheSequenceLoc,
"FF 05 ? ? ? ? B9 ? ? ? ? 8B F8 E8 ? ? ? ? 8B 44 24 1C 89 47 "
"18 8B 44 24 14");
ADDR BlScanText(
tsf_mCacheAllocatorLoc,
"89 35 ? ? ? ? C7 06 ? ? ? ? A1 ? ? ? ? 68 ? ? ? ? C7 40 ? ? ? ? ? E8 ? "
"? ? ? 83 C4 04 8B 4D F4 64 89 0D ? ? ? ? 59 5E 8B E5 5D C3");
ADDR BlScanText(tsf_gIdDictionaryLoc,
"89 15 ? ? ? ? E8 ? ? ? ? 8B F0 89 75 F0");
ADDR BlScanText(tsf_gEvalState_globalVarsLoc,
"B9 ? ? ? ? E8 ? ? ? ? 68 ? ? ? ? 6A 0A 68 ? ? ? ? B9 ? ? ? "
"? E8 ? ? ? ? E8 ? ? ? ?");
ADDR BlScanText(tsf_gIdDictionaryLoc, "89 15 ? ? ? ? E8 ? ? ? ? 8B F0 89 75 F0");
ADDR BlScanText(
tsf_gEvalState_globalVarsLoc,
"B9 ? ? ? ? E8 ? ? ? ? 68 ? ? ? ? 6A 0A 68 ? ? ? ? B9 ? ? ? "
"? E8 ? ? ? ? E8 ? ? ? ?");
tsf_mCacheSequence = *(ADDR *)(tsf_mCacheSequenceLoc + 2);
tsf_mCacheAllocator = *(ADDR *)(tsf_mCacheAllocatorLoc + 2);
tsf_gIdDictionary = *(ADDR *)(tsf_gIdDictionaryLoc + 2);
tsf_gEvalState_globalVars = *(ADDR *)(tsf_gEvalState_globalVarsLoc + 1);
tsf_mCacheSequence = *(ADDR*)(tsf_mCacheSequenceLoc + 2);
tsf_mCacheAllocator = *(ADDR*)(tsf_mCacheAllocatorLoc + 2);
tsf_gIdDictionary = *(ADDR*)(tsf_gIdDictionaryLoc + 2);
tsf_gEvalState_globalVars = *(ADDR*)(tsf_gEvalState_globalVarsLoc + 1);
return true;
}

View File

@@ -10,53 +10,44 @@
#include "BlHooks.hpp"
#endif
typedef const char *(*tsf_StringCallback)(ADDR, signed int, const char *[]);
typedef signed int (*tsf_IntCallback)(ADDR, signed int, const char *[]);
typedef float (*tsf_FloatCallback)(ADDR, signed int, const char *[]);
typedef void (*tsf_VoidCallback)(ADDR, signed int, const char *[]);
typedef bool (*tsf_BoolCallback)(ADDR, signed int, const char *[]);
typedef const char* (*tsf_StringCallback)(ADDR, signed int, const char*[]);
typedef signed int (*tsf_IntCallback)(ADDR, signed int, const char*[]);
typedef float (*tsf_FloatCallback)(ADDR, signed int, const char*[]);
typedef void (*tsf_VoidCallback)(ADDR, signed int, const char*[]);
typedef bool (*tsf_BoolCallback)(ADDR, signed int, const char*[]);
/* These functions are used for tsf_BlCon__executefSimObj.
They refer to a special buffer for the argument stack.
For tsf_BlCon__executef, you need to use your own buffers. */
char *tsf_GetIntArg(int);
char *tsf_GetFloatArg(float);
char *tsf_ScriptThis(ADDR);
char* tsf_GetIntArg(int);
char* tsf_GetFloatArg(float);
char* tsf_ScriptThis(ADDR);
const char *tsf_Eval(const char *);
const char *tsf_Evalf(const char *, ...);
const char* tsf_Eval(const char*);
const char* tsf_Evalf(const char*, ...);
ADDR tsf_FindObject(unsigned int);
ADDR tsf_FindObject(const char *);
ADDR tsf_FindObject(const char*);
ADDR tsf_LookupNamespace(const char *, const char *);
ADDR tsf_LookupNamespace(const char*, const char*);
const char *tsf_GetDataField(ADDR, const char *, const char *);
void tsf_SetDataField(ADDR, const char *, const char *, const char *);
const char* tsf_GetDataField(ADDR, const char*, const char*);
void tsf_SetDataField(ADDR, const char*, const char*, const char*);
const char *tsf_GetVar(const char *);
const char* tsf_GetVar(const char*);
void tsf_AddVarInternal(const char *, signed int, void *);
void tsf_AddVar(const char *, const char **);
void tsf_AddVar(const char *, signed int *);
void tsf_AddVar(const char *, float *);
void tsf_AddVar(const char *, bool *);
void tsf_AddVarInternal(const char*, signed int, void*);
void tsf_AddVar(const char*, const char**);
void tsf_AddVar(const char*, signed int*);
void tsf_AddVar(const char*, float*);
void tsf_AddVar(const char*, bool*);
ADDR tsf_AddConsoleFuncInternal(const char *, const char *, const char *,
signed int, const char *, signed int,
signed int);
void tsf_AddConsoleFunc(const char *, const char *, const char *,
tsf_StringCallback, const char *, signed int,
signed int);
void tsf_AddConsoleFunc(const char *, const char *, const char *,
tsf_IntCallback, const char *, signed int, signed int);
void tsf_AddConsoleFunc(const char *, const char *, const char *,
tsf_FloatCallback, const char *, signed int,
signed int);
void tsf_AddConsoleFunc(const char *, const char *, const char *,
tsf_VoidCallback, const char *, signed int, signed int);
void tsf_AddConsoleFunc(const char *, const char *, const char *,
tsf_BoolCallback, const char *, signed int, signed int);
ADDR tsf_AddConsoleFuncInternal(const char*, const char*, const char*, signed int, const char*, signed int, signed int);
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_StringCallback, const char*, signed int, signed int);
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_IntCallback, const char*, signed int, signed int);
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_FloatCallback, const char*, signed int, signed int);
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_VoidCallback, const char*, signed int, signed int);
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_BoolCallback, const char*, signed int, signed int);
bool tsf_InitInternal();
@@ -65,32 +56,20 @@ extern ADDR tsf_mCacheAllocator;
extern ADDR tsf_gIdDictionary;
extern ADDR tsf_gEvalState_globalVars;
BlFunctionDefExtern(const char *, __stdcall, tsf_BlStringTable__insert,
const char *, bool);
BlFunctionDefExtern(ADDR, __fastcall, tsf_BlNamespace__find, const char *,
const char *);
BlFunctionDefExtern(ADDR, __thiscall, tsf_BlNamespace__createLocalEntry, ADDR,
const char *);
BlFunctionDefExtern(const char*, __stdcall, tsf_BlStringTable__insert, const char*, bool);
BlFunctionDefExtern(ADDR, __fastcall, tsf_BlNamespace__find, const char*, const char*);
BlFunctionDefExtern(ADDR, __thiscall, tsf_BlNamespace__createLocalEntry, ADDR, const char*);
BlFunctionDefExtern(void, __thiscall, tsf_BlDataChunker__freeBlocks, ADDR);
BlFunctionDefExtern(const char *, , tsf_BlCon__evaluate, ADDR, signed int,
const char **);
BlFunctionDefExtern(const char *, , tsf_BlCon__executef, signed int, ...);
BlFunctionDefExtern(const char *, , tsf_BlCon__executefSimObj, ADDR *,
signed int, ...);
BlFunctionDefExtern(const char *, __thiscall, tsf_BlCon__getVariable,
const char *);
BlFunctionDefExtern(void, __thiscall, tsf_BlDictionary__addVariable, ADDR *,
const char *, signed int, void *);
BlFunctionDefExtern(ADDR *, __thiscall, tsf_BlSim__findObject_name,
const char *);
BlFunctionDefExtern(char *, __stdcall, tsf_BlStringStack__getArgBuffer,
unsigned int);
BlFunctionDefExtern(const char *, __thiscall, tsf_BlSimObject__getDataField,
ADDR, const char *, const char *);
BlFunctionDefExtern(void, __thiscall, tsf_BlSimObject__setDataField, ADDR,
const char *, const char *, const char *);
BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer,
unsigned int);
BlFunctionDefExtern(const char*, , tsf_BlCon__evaluate, ADDR, signed int, const char**);
BlFunctionDefExtern(const char*, , tsf_BlCon__executef, signed int, ...);
BlFunctionDefExtern(const char*, , tsf_BlCon__executefSimObj, ADDR*, signed int, ...);
BlFunctionDefExtern(const char*, __thiscall, tsf_BlCon__getVariable, const char*);
BlFunctionDefExtern(void, __thiscall, tsf_BlDictionary__addVariable, ADDR*, const char*, signed int, void*);
BlFunctionDefExtern(ADDR*, __thiscall, tsf_BlSim__findObject_name, const char*);
BlFunctionDefExtern(char*, __stdcall, tsf_BlStringStack__getArgBuffer, unsigned int);
BlFunctionDefExtern(const char*, __thiscall, tsf_BlSimObject__getDataField, ADDR, const char*, const char*);
BlFunctionDefExtern(void, __thiscall, tsf_BlSimObject__setDataField, ADDR, const char*, const char*, const char*);
BlFunctionDefExtern(char*, __fastcall, tsf_BlCon__getReturnBuffer, unsigned int);
// Function short names
@@ -100,7 +79,7 @@ BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer,
#define BlIntArg tsf_GetIntArg
#define BlFloatArg tsf_GetFloatArg
#define BlThisArg tsf_GetThisArg
#define BlStringArg(x) tsf_GetStringArg((char *)x)
#define BlStringArg(x) tsf_GetStringArg((char*)x)
#define BlReturnBuffer tsf_BlCon__getReturnBuffer
#define BlObject tsf_FindObject
@@ -114,23 +93,21 @@ BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer,
#define BlAddFunction tsf_AddConsoleFunc
#define __22ND_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, \
a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, ...) \
#define __22ND_ARGUMENT( \
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, ...) \
a22
#define __NUM_LIST(...) \
__22ND_ARGUMENT(dummy, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, \
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __NUM_LIST(...) \
__22ND_ARGUMENT(dummy, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define BlCall(...) tsf_BlCon__executef(__NUM_LIST(__VA_ARGS__), __VA_ARGS__)
#define BlCallObj(obj, ...) \
tsf_BlCon__executefSimObj((ADDR *)obj, __NUM_LIST(__VA_ARGS__), __VA_ARGS__)
#define BlCallObj(obj, ...) tsf_BlCon__executefSimObj((ADDR*)obj, __NUM_LIST(__VA_ARGS__), __VA_ARGS__)
#define BlFuncsInit() \
if (!tsf_InitInternal()) { \
return false; \
#define BlFuncsInit() \
if (!tsf_InitInternal()) { \
return false; \
}
#define BlFuncsDeinit() \
if (!tsf_DeinitInternal()) { \
return false; \
#define BlFuncsDeinit() \
if (!tsf_DeinitInternal()) { \
return false; \
}
#endif

View File

@@ -27,14 +27,13 @@ void tsh_i_InitScanner() {
HMODULE module = GetModuleHandle(NULL);
if (module) {
MODULEINFO info;
GetModuleInformation(GetCurrentProcess(), module, &info,
sizeof(MODULEINFO));
GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO));
ImageBase = (ADDR)info.lpBaseOfDll;
ImageSize = info.SizeOfImage;
}
}
bool tsh_i_CompareData(BYTE *data, BYTE *pattern, char *mask) {
bool tsh_i_CompareData(BYTE* data, BYTE* pattern, char* mask) {
for (; *mask; ++data, ++pattern, ++mask) {
if (*mask == 'x' && *data != *pattern)
return false;
@@ -42,8 +41,7 @@ bool tsh_i_CompareData(BYTE *data, BYTE *pattern, char *mask) {
return (*mask) == 0;
}
ADDR tsh_i_FindPattern(ADDR imageBase, ADDR imageSize, BYTE *pattern,
char *mask) {
ADDR tsh_i_FindPattern(ADDR imageBase, ADDR imageSize, BYTE* pattern, char* mask) {
for (ADDR i = imageBase; i < imageBase + imageSize; i++) {
if (tsh_i_CompareData((PBYTE)i, pattern, mask)) {
return i;
@@ -53,10 +51,10 @@ ADDR tsh_i_FindPattern(ADDR imageBase, ADDR imageSize, BYTE *pattern,
}
// Convert a text-style pattern into code-style
void tsh_i_PatternTextToCode(char *text, char **opatt, char **omask) {
void tsh_i_PatternTextToCode(char* text, char** opatt, char** omask) {
unsigned int len = strlen(text);
char *patt = (char *)malloc(len);
char *mask = (char *)malloc(len);
char* patt = (char*)malloc(len);
char* mask = (char*)malloc(len);
int outidx = 0;
int val = 0;
@@ -93,15 +91,14 @@ void tsh_i_PatternTextToCode(char *text, char **opatt, char **omask) {
// Public functions for sig scanning
// Scan using code-style pattern
ADDR tsh_ScanCode(char *pattern, char *mask) {
return tsh_i_FindPattern(ImageBase, ImageSize - strlen(mask), (BYTE *)pattern,
mask);
ADDR tsh_ScanCode(char* pattern, char* mask) {
return tsh_i_FindPattern(ImageBase, ImageSize - strlen(mask), (BYTE*)pattern, mask);
}
// Scan using a text-style pattern
ADDR tsh_ScanText(char *text) {
char *patt;
char *mask;
ADDR tsh_ScanText(char* text) {
char* patt;
char* mask;
tsh_i_PatternTextToCode(text, &patt, &mask);
ADDR res = tsh_ScanCode(patt, mask);
@@ -119,54 +116,46 @@ ADDR tsh_ScanText(char *text) {
void tsh_DeprotectAddress(ADDR length, ADDR location) {
DWORD oldProtection;
VirtualProtect((void *)location, length, PAGE_EXECUTE_READWRITE,
&oldProtection);
VirtualProtect((void*)location, length, PAGE_EXECUTE_READWRITE, &oldProtection);
// tsh_DeprotectedAddresses[location] = {length, oldProtection};
}
// Patch a string of bytes by deprotecting and then overwriting
void tsh_PatchBytes(ADDR length, ADDR location, BYTE *repl) {
void tsh_PatchBytes(ADDR length, ADDR location, BYTE* repl) {
tsh_DeprotectAddress(length, location);
memcpy((void *)location, (void *)repl, (size_t)length);
memcpy((void*)location, (void*)repl, (size_t)length);
}
void tsh_PatchByte(ADDR location, BYTE value) {
tsh_PatchBytes(location, 1, &value);
}
void tsh_PatchByte(ADDR location, BYTE value) { tsh_PatchBytes(location, 1, &value); }
void tsh_ReplaceInt(ADDR addr, int rval) {
tsh_PatchBytes(4, addr, (BYTE *)(&rval));
}
void tsh_ReplaceInt(ADDR addr, int rval) { tsh_PatchBytes(4, addr, (BYTE*)(&rval)); }
int tsh_i_CallOffset(ADDR instr, ADDR func) { return func - (instr + 4); }
void tsh_i_ReplaceCall(ADDR instr, ADDR target) {
tsh_ReplaceInt(instr, tsh_i_CallOffset(instr, target));
}
void tsh_i_ReplaceCall(ADDR instr, ADDR target) { tsh_ReplaceInt(instr, tsh_i_CallOffset(instr, target)); }
void tsh_i_PatchCopy(ADDR dest, ADDR src, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
tsh_PatchByte(dest + i, *((BYTE *)(src + i)));
tsh_PatchByte(dest + i, *((BYTE*)(src + i)));
}
}
void tsh_HookFunction(ADDR victim, ADDR detour, BYTE *origbytes) {
memcpy(origbytes, (BYTE *)victim, 6); // save old data
void tsh_HookFunction(ADDR victim, ADDR detour, BYTE* origbytes) {
memcpy(origbytes, (BYTE*)victim, 6); // save old data
*(BYTE *)victim = 0xE9; // jmp rel32
*(ADDR *)(victim + 1) = (detour - (victim + 5)); // jump offset
*(BYTE *)(victim + 5) = 0xC3; // retn
*(BYTE*)victim = 0xE9; // jmp rel32
*(ADDR*)(victim + 1) = (detour - (victim + 5)); // jump offset
*(BYTE*)(victim + 5) = 0xC3; // retn
}
void tsh_UnhookFunction(ADDR victim, BYTE *origbytes) {
void tsh_UnhookFunction(ADDR victim, BYTE* origbytes) {
tsh_i_PatchCopy(victim, (ADDR)origbytes, 6); // restore old data
}
int tsh_PatchAllMatchesCode(ADDR len, char *patt, char *mask, char *replace,
bool debugprint) {
int tsh_PatchAllMatchesCode(ADDR len, char* patt, char* mask, char* replace, bool debugprint) {
int numpatched = 0;
for (ADDR i = ImageBase; i < ImageBase + ImageSize - len; i++) {
if (tsh_i_CompareData((BYTE *)i, (BYTE *)patt, mask)) {
if (tsh_i_CompareData((BYTE*)i, (BYTE*)patt, mask)) {
if (debugprint)
BlPrintf("RedoBlHooks: Patching call at %08x", i);
@@ -180,10 +169,9 @@ int tsh_PatchAllMatchesCode(ADDR len, char *patt, char *mask, char *replace,
return numpatched;
}
int tsh_PatchAllMatchesHex(ADDR len, char *text, char *replace,
bool debugprint) {
char *patt;
char *mask;
int tsh_PatchAllMatchesHex(ADDR len, char* text, char* replace, bool debugprint) {
char* patt;
char* mask;
tsh_i_PatternTextToCode(text, &patt, &mask);
int res = tsh_PatchAllMatchesCode(len, patt, mask, replace, debugprint);
@@ -199,9 +187,7 @@ int tsh_PatchAllMatchesHex(ADDR len, char *text, char *replace,
bool tsh_InitInternal() {
tsh_i_InitScanner();
BlScanFunctionText(
tsh_BlPrintf,
"8D 44 24 08 33 D2 50 FF 74 24 08 33 C9 E8 ? ? ? ? 83 C4 08 C3");
BlScanFunctionText(tsh_BlPrintf, "8D 44 24 08 33 D2 50 FF 74 24 08 33 C9 E8 ? ? ? ? 83 C4 08 C3");
return true;
}

View File

@@ -14,13 +14,13 @@ typedef unsigned int ADDR;
bool tsh_InitInternal();
bool tsh_DeinitInternal();
ADDR tsh_ScanCode(char *, char *);
ADDR tsh_ScanText(char *);
void tsh_HookFunction(ADDR, ADDR, BYTE *);
void tsh_UnhookFunction(ADDR, BYTE *);
int tsh_PatchAllMatches(unsigned int, char *, char *, char *, bool);
ADDR tsh_ScanCode(char*, char*);
ADDR tsh_ScanText(char*);
void tsh_HookFunction(ADDR, ADDR, BYTE*);
void tsh_UnhookFunction(ADDR, BYTE*);
int tsh_PatchAllMatches(unsigned int, char*, char*, char*, bool);
void tsh_PatchByte(ADDR, BYTE);
void tsh_PatchBytes(unsigned int, ADDR, BYTE *);
void tsh_PatchBytes(unsigned int, ADDR, BYTE*);
void tsh_PatchInt(ADDR, int);
// Debug print settings
@@ -34,13 +34,13 @@ void tsh_PatchInt(ADDR, int);
// Function short names
// Use in code when the def is not shared in a header
#define BlFunctionDef(returnType, convention, name, ...) \
typedef returnType(convention *tsh_##name##FnT)(__VA_ARGS__); \
#define BlFunctionDef(returnType, convention, name, ...) \
typedef returnType(convention* tsh_##name##FnT)(__VA_ARGS__); \
tsh_##name##FnT name;
// Use in header for shared function defs when a BlFunctionDefIntern exists in
// code
#define BlFunctionDefExtern(returnType, convention, name, ...) \
typedef returnType(convention *tsh_##name##FnT)(__VA_ARGS__); \
#define BlFunctionDefExtern(returnType, convention, name, ...) \
typedef returnType(convention* tsh_##name##FnT)(__VA_ARGS__); \
extern tsh_##name##FnT name;
// Use in code for shared function defs when a BlFunctionDefExtern exists in
// header
@@ -48,94 +48,84 @@ void tsh_PatchInt(ADDR, int);
// Scan for and assign the pattern to the variable, or err and return if not
// found
#define BlScanFunctionCode(target, patt, mask) \
target = (tsh_##target##FnT)tsh_ScanCode((char *)patt, (char *)mask); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found function " #target " at %08x", \
(int)target); \
#define BlScanFunctionCode(target, patt, mask) \
target = (tsh_##target##FnT)tsh_ScanCode((char*)patt, (char*)mask); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found function " #target " at %08x", (int)target); \
}
#define BlScanFunctionText(target, text) \
target = (tsh_##target##FnT)tsh_ScanText((char *)text); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found function " #target " at %08x", \
(int)target); \
#define BlScanFunctionText(target, text) \
target = (tsh_##target##FnT)tsh_ScanText((char*)text); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found function " #target " at %08x", (int)target); \
}
#define BlScanCode(target, patt, mask) \
target = tsh_ScanCode((char *)patt, (char *)mask); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find pattern " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
#define BlScanCode(target, patt, mask) \
target = tsh_ScanCode((char*)patt, (char*)mask); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find pattern " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
}
#define BlScanText(target, text) \
target = tsh_ScanText((char *)text); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
#define BlScanText(target, text) \
target = tsh_ScanText((char*)text); \
if (!target) { \
BlPrintf("RedoBlHooks | Cannot find " #target "!"); \
return false; \
} else { \
if (tsh_DEBUGPRINT) \
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
}
// Use in code to define the data and functions for hooking a function
#define BlFunctionHookDef(func) \
BYTE tsh_BlFunctionHook##func##Data[6]; \
void func##HookOn() { \
tsh_HookFunction((ADDR)func, (ADDR)func##Hook, \
tsh_BlFunctionHook##func##Data); \
} \
void func##HookOff() { \
tsh_UnhookFunction((ADDR)func, tsh_BlFunctionHook##func##Data); \
}
#define BlFunctionHookDef(func) \
BYTE tsh_BlFunctionHook##func##Data[6]; \
void func##HookOn() { tsh_HookFunction((ADDR)func, (ADDR)func##Hook, tsh_BlFunctionHook##func##Data); } \
void func##HookOff() { tsh_UnhookFunction((ADDR)func, tsh_BlFunctionHook##func##Data); }
// Use in code to initialize the hook once
#define BlFunctionHookInit(func) \
tsh_DeprotectAddress(6, (ADDR)func); \
#define BlFunctionHookInit(func) \
tsh_DeprotectAddress(6, (ADDR)func); \
func##HookOn();
// Replace all matches of the pattern with the given byte string
#define BlPatchAllMatchesCode(len, patt, mask, repl) \
tsh_PatchAllMatchesCode((ADDR)len, (char *)patt, (char *)mask, (char *)repl, \
tsh_DEBUGPRINT);
#define BlPatchAllMatchesText(len, text, repl) \
tsh_PatchAllMatchesCode((ADDR)len, (char *)text, (char *)repl, \
tsh_DEBUGPRINT);
#define BlPatchAllMatchesCode(len, patt, mask, repl) \
tsh_PatchAllMatchesCode((ADDR)len, (char*)patt, (char*)mask, (char*)repl, tsh_DEBUGPRINT);
#define BlPatchAllMatchesText(len, text, repl) \
tsh_PatchAllMatchesCode((ADDR)len, (char*)text, (char*)repl, tsh_DEBUGPRINT);
// Deprotect and replace one byte
#define BlPatchByte(addr, byte) tsh_PatchByte((ADDR)addr, (BYTE)byte);
// Deprotect and replace a byte string
#define BlPatchBytes(len, addr, repl) \
tsh_PatchBytes((ADDR)len, (ADDR)addr, (BYTE *)repl);
#define BlPatchBytes(len, addr, repl) tsh_PatchBytes((ADDR)len, (ADDR)addr, (BYTE*)repl);
// BlPrintf(char* format, ...)
#define BlPrintf(...) \
if (tsh_BlPrintf) { \
tsh_BlPrintf(__VA_ARGS__); \
#define BlPrintf(...) \
if (tsh_BlPrintf) { \
tsh_BlPrintf(__VA_ARGS__); \
}
// BlHooksInit() -> bool: success
#define BlHooksInit() \
if (!tsh_InitInternal()) { \
BlPrintf("BlHooksInit failed"); \
return false; \
#define BlHooksInit() \
if (!tsh_InitInternal()) { \
BlPrintf("BlHooksInit failed"); \
return false; \
}
// BlHooksDeinit() -> bool: success
#define BlHooksDeinit() \
if (!tsh_DeinitInternal()) { \
BlPrintf("BlHooksDeinit failed"); \
return false; \
#define BlHooksDeinit() \
if (!tsh_DeinitInternal()) { \
BlPrintf("BlHooksDeinit failed"); \
return false; \
}
// Scanned structures
BlFunctionDefExtern(void, , tsh_BlPrintf, const char *, ...);
BlFunctionDefExtern(void, , tsh_BlPrintf, const char*, ...);
#endif

351
readme.md
View File

@@ -1,203 +1,240 @@
# BlockLua
Lua scripting for Blockland
## How to Install
- Install RedBlocklandLoader
- Copy `lua5.1.dll` into your Blockland install folder, next to `Blockland.exe`
- Copy `BlockLua.dll` into the `modules` folder within the Blockland folder
- Install RedBlocklandLoader
- Copy `lua5.1.dll` into your Blockland install folder, next to `Blockland.exe`
- Copy `BlockLua.dll` into the `modules` folder within the Blockland folder
## Quick Reference
### From TorqueScript
`'print('hello world')` - Execute Lua in the console by prepending a `'` (single quote)
`luaeval("code");` - Execute Lua code
`luacall("funcName", %args...);` - Call a Lua global function
`luaexec("fileName");` - Execute a Lua file. Path rules are the same as executing .cs files.
`luaget("varName");` - Read a Lua global variable
`luaset("varName", %value);` - Write a Lua global variable
`'print('hello world')` - Execute Lua in the console by prepending a `'` (single quote)
`luaeval("code");` - Execute Lua code
`luacall("funcName", %args...);` - Call a Lua function (supports indexing tables and object methods)
`luaexec("fileName");` - Execute a Lua file. Path rules are the same as when executing .cs files, relative paths are allowed.
`luaget("varName");` - Read a Lua global variable (supports indexing tables)
`luaset("varName", %value);` - Write a Lua global variable (supports indexing tables)
### From Lua
`bl.eval('code')` - Eval TorqueScript code
`bl.funcName(args)` - Call a TorqueScript function
`bl.varName` - Read a TorqueScript global variable
`bl['varName']` - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array)
`bl.set('varName', value)` - Write a TorqueScript global variable
`bl.eval('code')` - Eval TorqueScript code
`bl.funcName(args)` - Call a TorqueScript function
`bl.varName` - Read a TorqueScript global variable
`bl['varName']` - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array)
`bl.set('varName', value)` - Write a TorqueScript global variable
`bl['namespaceName::funcName'](args)` - Call a namespaced TorqueScript function
### Accessing Torque Objects from Lua
`bl.objectName` - Access a Torque object by name
`bl[objectID]` - Access a Torque object by ID (or name)
`object.fieldOrKey` - Read a field or Lua key from a Torque object
`object:set('field', value)` - Write a field on a Torque object
`object.key = value` - Associate Lua data with a Torque object
`object:method(args)` - Call a Torque object method
`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.
`bl.objectName` - Access a Torque object by name
`bl[objectID]` - Access a Torque object by ID (or name)
`object.fieldOrKey` - Read a field or Lua key from a Torque object
`object:set('field', value)` - Write a field on a Torque object
`object.key = value` - Associate Lua data with a Torque object
`object:method(args)` - Call a Torque object method
`object[index]` - Access a member of a Torque set or group
`for child in object:members() do` - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
`bl.isObject(object, objectID, or 'objectName')` - Check if an object exists
`object:exists()` - Check if an object exists
### Timing/Schedules
`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 = 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
### 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.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.
`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.radiusSearch(vector{centerX,y,z}, radius, 'objtype'/{'objtypes',...}) do` - Find all objects of the specified type(s) whose bounding box overlaps with the specified sphere. See the Types section for a list of valid object types.
### List of Object Classes (for raycasts and searches)
`'all'` - Any object
`'player'` - Players or bots
`'item'` - Items
`'vehicle'` - Vehicles
`'projectile'` - Projectiles
`'brick'` - Bricks with raycasting enabled
`'brickalways'` - All bricks including those with raycasting disabled
Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'`
### Server-Client Communication
`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
`bl.addServerCmd('commandName', function(client, args...) ... end)` - Register a /command on the server
`bl.addClientCmd('commandName', function(args...) ... end)` - Register a client command on the client
`bl.commandToServer('commandName', args...)` - As a client, execute a server command
`bl.commandToClient(client, 'commandName', args...)` - As the server, execute a client command on a specific client
`bl.commandToAll('commandName', args...)` - As the server, execute a client command on all clients
### Packages/Hooks
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) yourCode end)` - Hook a Torque function with a Lua function.
`args` is an array containing the arguments provided to the function. If the hook is `before`, these can be modified before being passed to the parent function.
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
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) ... end)` - Hook a Torque function with a Lua function.
`args` is an array containing the arguments provided to the function. If the hook is `before`, these can be modified before being passed to the parent function.
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
### Modules and Dependencies
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
`require('modulePath.moduleName')` - Load a Lua file or external library.
`require` replaces `.` with `/` in the path, and then searches for files in the following order:
- `./modulePath/moduleName.lua`
- `./modulePath/moduleName/init.lua`
- `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`.
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
`require('modulePath.moduleName')` - Load a Lua file or external library.
`require` replaces `.` with `/` in the path, and then searches for files in the following order:
- `./modulePath/moduleName.lua`
- `./modulePath/moduleName/init.lua`
- `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
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
Relative paths (`./`) are allowed. `..` is not allowed.
`file = io.open('./file.txt', 'r'/'w'/'a'/'rb'/'wb'/'ab')` - Open a file
`file:read(numberOfChars/'*a')` - Read an opened file (must be opened in 'r' (read) or 'rb' (read binary) mode)
`file:write(string)` - Write an opened file (must be opened in 'w' (write), 'a' (append), 'wb' or 'ab' mode)
`file:close()` - Close an opened file
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.
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
Relative paths (`./`) are allowed. `..` is not allowed.
`file = io.open('./file.txt', 'r'/'w'/'a'/'rb'/'wb'/'ab')` - Open a file
`file:read(numberOfChars/'*a')` - Read an opened file (must be opened in 'r' (read) or 'rb' (read binary) mode)
`file:write(string)` - Write an opened file (must be opened in 'w' (write), 'a' (append), 'wb' or 'ab' mode)
`file:close()` - Close an opened file
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.
### Object Creation
`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
`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
### Classes and Types
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', 'string' (prevents automatic conversion), and nil (default, applies automatic conversion).
`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.
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
`bl.boolean(thing)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
`bl.object(thing)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
### 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
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', 'string' (prevents automatic conversion), and nil (default, applies automatic conversion).
`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.
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
`bl.boolean(arg)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
`bl.object(arg)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
`bl.string(arg)` - Manually convert any automatically-converted Torque value back into a string. This is not as reliable as using `bl.type` to specify the type as a string beforehand.
### Vector
`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.
### Matrix
WIP
### 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)`
`str[index]`
`str[{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.mapk(func, ...)`
`table.map_list(func, ...)`
`table.mapi_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
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.
### From TorqueScript to Lua
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
- The empty string "" becomes `nil`
- 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
- Any other string is passed directly as a `string`
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.
### From Lua to TorqueScript
- `nil` becomes the empty string ""
- `true` and `false` become "1" and "0" respectively
- Torque containers become their object ID
- A `vector` becomes a string containing three numbers separated by spaces
- A table of two vectors becomes a string containing six numbers separated by spaces
- Any `string` is passed directly as a string
- Tables cannot be passed and will throw an error
- `nil` becomes the empty string ""
- `true` and `false` become "1" and "0" respectively
- A Torque object container becomes its object ID
- A `vector` becomes a string containing three numbers separated by spaces
- A table of two `vector`s becomes a string containing six numbers separated by spaces
- (WIP) A `matrix` is converted into an axis-angle (a "transform"), a string containing seven numbers separated by spaces
- Any `string` is passed directly as a string
- Tables cannot be passed and will throw an error
### From TorqueScript to Lua
- The empty string "" becomes `nil`
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
- A string containing two or three numbers separated by single spaces becomes a `vector`
- A string containing six numbers separated by single spaces becomes a table of two vectors, usually defining the corners a bounding box
- (WIP) A string containing seven numbers separated by single spaces is treated as an axis-angle (a "transform"), and is converted into a `matrix` representing the translation and rotation
- Any other string is passed directly as a `string`
For scenarios where the automatic TorqueScript->Lua conversion rules are insufficient or incorrect, use `bl.type`.
To convert things by hand, use `bl.object`, `bl.boolean`, or `bl.string`.
## I/O and Safety
All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is.
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
### Unsafe Mode
BlockLua can be built in Unsafe Mode by specifying the `-DBLLUA_UNSAFE` compiler flag. This removes the sandboxing of Lua code, allowing it to access any file and use any library, including ffi.
Please do not publish add-ons that require unsafe mode.
### List of Object Types
`'all'` - Any object
`'player'` - Players or bots
`'item'` - Items
`'vehicle'` - Vehicles
`'projectile'` - Projectiles
`'brick'` - Bricks with raycasting enabled
`'brickalways'` - All bricks including those with raycasting disabled
Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'`
All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is.
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
### Unsafe Mode
BlockLua can be built in Unsafe Mode by specifying the `-DBLLUA_UNSAFE` compiler flag. This removes the sandboxing of Lua code, allowing it to access any file and use any library, including ffi.
A more limited option is `-DBLLUA_ALLOWFFI`, which allows the use of the `ffi` library. This can still be exploited to grant all the same access as full unsafe mode.
Please do not publish add-ons that require either of these.
## Compiling
With any *32-bit* variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
`g++ src/bllua4.cpp -o BlockLua.dll -m32 -shared -static-libgcc -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 src/bllua`
With any _32-bit_ variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
`g++ src/bllua4.cpp -o BlockLua.dll -m32 -shared -static-libgcc -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1`
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/

View File

@@ -1,4 +1,4 @@
// BlockLua (bllua4): Simple Lua interface for TorqueScript
// BlockLua (bllua4): Advanced Lua interface for TorqueScript
// Includes
@@ -14,7 +14,7 @@
#include "luainterp.cpp"
#include "lualibts.cpp"
lua_State *gL;
lua_State* gL;
#include "tsliblua.cpp"
// Global variables
@@ -22,15 +22,16 @@ lua_State *gL;
// Setup
// Hack to encode the contents of text files as static strings
#define INCLUDE_BIN(varname, filename) \
asm("_" #varname ": .incbin \"" filename "\""); \
asm(".byte 0"); \
#define INCLUDE_BIN(varname, filename) \
asm("_" #varname ": .incbin \"" filename "\""); \
asm(".byte 0"); \
extern char varname[];
INCLUDE_BIN(bll_fileLuaEnvSafe, "lua-env-safe.lua");
INCLUDE_BIN(bll_fileLuaEnv, "lua-env.lua");
INCLUDE_BIN(bll_fileTsEnv, "ts-env.cs");
INCLUDE_BIN(bll_fileLuaStd, "util/std.lua");
INCLUDE_BIN(bll_fileLuaVector, "util/vector.lua");
INCLUDE_BIN(bll_fileLuaMatrix, "util/matrix.lua");
INCLUDE_BIN(bll_fileLuaLibts, "util/libts-lua.lua");
INCLUDE_BIN(bll_fileTsLibts, "util/libts-ts.cs");
INCLUDE_BIN(bll_fileLuaLibbl, "util/libbl.lua");
@@ -38,10 +39,10 @@ INCLUDE_BIN(bll_fileLuaLibblTypes, "util/libbl-types.lua");
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
INCLUDE_BIN(bll_fileLoadaddons, "util/loadaddons.cs");
#define BLL_LOAD_LUA(lstate, vname) \
if (!bll_LuaEval(lstate, vname)) { \
BlPrintf(" Error executing " #vname); \
return false; \
#define BLL_LOAD_LUA(lstate, vname) \
if (!bll_LuaEval(lstate, vname)) { \
BlPrintf(" Error executing " #vname); \
return false; \
}
bool init() {
@@ -59,23 +60,27 @@ bool init() {
// Set up Lua environment
BLL_LOAD_LUA(gL, bll_fileLuaEnv);
#ifdef BLLUA_ALLOWFFI
lua_pushboolean(gL, true);
lua_setglobal(gL, "_bllua_allowffi");
#endif
#ifndef BLLUA_UNSAFE
BLL_LOAD_LUA(gL, bll_fileLuaEnvSafe);
#endif
// Expose Lua API to TS
BlAddFunction(NULL, NULL, "_bllua_luacall", bll_ts_luacall,
"LuaCall(name, ...) - Call Lua function and return result", 2,
20);
BlEval(bll_fileTsEnv);
// Load utilities
// Load utilities in Lua
BLL_LOAD_LUA(gL, bll_fileLuaStd);
BLL_LOAD_LUA(gL, bll_fileLuaVector);
BLL_LOAD_LUA(gL, bll_fileLuaMatrix);
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
BlEval(bll_fileTsLibts);
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
// Expose Lua API to TS
BlAddFunction(
NULL, NULL, "_bllua_luacall", bll_ts_luacall, "LuaCall(name, ...) - Call Lua function and return result", 2, 20);
BlEval(bll_fileTsEnv);
BlEval(bll_fileTsLibts);
BlEval(bll_fileTsLibblSupport);
BlEval(bll_fileLoadaddons);
@@ -88,8 +93,7 @@ bool init() {
bool deinit() {
BlPrintf("BlockLua: Unloading");
BlEval("deactivatePackage(_bllua_main);");
BlEval("$_bllua_active = 0;");
BlEval("$_bllua_active=0;deactivatePackage(_bllua_main);");
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
lua_close(gL);
@@ -101,7 +105,7 @@ bool deinit() {
return true;
}
bool __stdcall DllMain(HINSTANCE hinstance, DWORD reason, void *reserved) {
bool __stdcall DllMain(HINSTANCE hinstance, DWORD reason, void* reserved) {
switch (reason) {
case DLL_PROCESS_ATTACH:
return init();

View File

@@ -14,6 +14,7 @@ local old_require = require
local old_os = os
local old_debug = debug
local old_package = package
local old_allowffi = _bllua_allowffi
-- Remove all global variables except a whitelist
local ok_names = tmap {
@@ -39,13 +40,10 @@ end
-- Sanitize file paths to point only to allowed files within the game directory
-- List of allowed directories for reading/writing
-- modules/lualib is also allowed as read-only
local allowed_dirs = tmap {
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
}
-- List of allowed directories for reading only
local allowed_dirs_readonly = tmap {
'lualib'
}
-- List of disallowed file extensions - basically executable file extensions
-- Note that even without this protection, exploiting would still require somehow
-- getting a file within the allowed directories to autorun,
@@ -64,6 +62,9 @@ local disallowed_exts = tmap {
-- Return: clean file path if allowed (or nil if disallowed),
-- error string (or nil if allowed)
local function safe_path(fn, readonly)
if type(fn) ~= 'string' then
return nil, 'Filename must be a string'
end
fn = fn:gsub('\\', '/')
fn = fn:gsub('^ +', '')
fn = fn:gsub(' +$', '')
@@ -81,14 +82,15 @@ local function safe_path(fn, readonly)
end
-- allow only whitelisted dirs
local dir = fn:match('^([^/]+)/')
if (not dir) or (
(not allowed_dirs[dir:lower()]) and
((not readonly) or (not allowed_dirs_readonly[dir:lower()]))) then
return nil, 'filename is in disallowed directory ' .. (dir or 'nil')
if not (dir and (
allowed_dirs[dir:lower()] or
(readonly and fn:find('^modules/lualib/'))))
then
return nil, 'File is in disallowed directory ' .. (dir or 'nil')
end
-- disallow blacklisted extensions or no extension
-- disallow blacklisted extensions
local ext = fn:match('%.([^/%.]+)$')
if (not ext) or (disallowed_exts[ext:lower()]) then
if ext and disallowed_exts[ext:lower()] then
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
(ext or '') .. '\''
end
@@ -120,6 +122,7 @@ local disallowed_packages = tmap {
'ffi', 'debug', 'package', 'io', 'os',
'_bllua_ts',
}
if old_allowffi then disallowed_packages['ffi'] = nil end
function _bllua_requiresecure(name)
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
name:find('^%.') or name:find('%.$') then
@@ -143,4 +146,5 @@ debug = {
getfilename = old_debug.getfilename, -- defined in lua.env.lua
}
_bllua_ts.echo(' Executed bllua-env-safe.lua')
print = _bllua_ts.echo
print(' Executed bllua-env-safe.lua')

View File

@@ -18,6 +18,8 @@ end
-- Called when pcall fails on a ts->lua call, used to print detailed error info
function _bllua_on_error(err)
-- Convert error to string if it's not already
err = tostring(err)
err = err:match(': (.+)$') or err
local tracelines = { err }
local level = 2
@@ -25,7 +27,7 @@ function _bllua_on_error(err)
local info = debug.getinfo(level)
if not info then break end
local filename = debug.getfilename(level) or info.short_src
local funcname = info.name
local funcname = info.name or '<unknown>'
if funcname == 'dofile' then break end
table.insert(tracelines, string.format('%s:%s in function \'%s\'',
filename,
@@ -37,4 +39,9 @@ function _bllua_on_error(err)
return table.concat(tracelines, '\n')
end
_bllua_ts.echo(' Executed bllua-env.lua')
-- overridden in lua-env-safe.lua (executed if not BLLUA_UNSAFE)
_bllua_io_open = io.open
_bllua_requiresecure = require
print = _bllua_ts.echo
print(' Executed bllua-env.lua')

View File

@@ -5,7 +5,8 @@
#include "lauxlib.h"
#include "lua.h"
#include <cstring>
int bll_error_handler(lua_State *L) {
int bll_error_handler(lua_State* L) {
lua_getfield(L, LUA_GLOBALSINDEX, "_bllua_on_error");
if (!lua_isfunction(L, -1)) {
BlPrintf(" Lua error handler: _bllua_on_error not defined.");
@@ -20,7 +21,8 @@ int bll_error_handler(lua_State *L) {
lua_pcall(L, 1, 1, 0);
return 1;
}
int bll_pcall(lua_State *L, int nargs, int nret) {
int bll_pcall(lua_State* L, int nargs, int nret) {
// calculate stack position for message handler
int hpos = lua_gettop(L) - nargs;
// push custom error message handler
@@ -35,7 +37,7 @@ int bll_pcall(lua_State *L, int nargs, int nret) {
}
// Display the last Lua error in the BL console
void bll_printError(lua_State *L, const char *operation, const char *item) {
void bll_printError(lua_State* L, const char* operation, const char* item) {
// error_handler(L);
BlPrintf("\x03Lua error: %s", lua_tostring(L, -1));
BlPrintf("\x03 (%s: %s)", operation, item);
@@ -43,7 +45,7 @@ void bll_printError(lua_State *L, const char *operation, const char *item) {
}
// Eval a string of Lua code
bool bll_LuaEval(lua_State *L, const char *str) {
bool bll_LuaEval(lua_State* L, const char* str) {
if (luaL_loadbuffer(L, str, strlen(str), "input") || bll_pcall(L, 0, 1)) {
bll_printError(L, "eval", str);
return false;
@@ -54,9 +56,10 @@ bool bll_LuaEval(lua_State *L, const char *str) {
// Convert a Lua stack entry into a string for providing to TS
// Use static buffer to avoid excessive malloc
char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
bool bll_toarg(lua_State *L, char *buf, int i, bool err) {
bool bll_toarg(lua_State* L, char* buf, int i, bool err) {
if (lua_isstring(L, i)) {
const char *str = lua_tostring(L, i);
const char* str = lua_tostring(L, i);
if (strlen(str) >= BLL_ARG_MAX) {
if (err)
luaL_error(L, "argument to TS is too long - max length is 8192");

View File

@@ -3,14 +3,15 @@
#define _H_LUAINTERP_SHARED
#include "lua.h"
#define BLL_ARG_COUNT 20
#define BLL_ARG_MAX 8192
extern char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
bool bll_toarg(lua_State *L, char *buf, int i, bool err);
int bll_pcall(lua_State *L, int nargs, int nret);
void bll_printError(lua_State *L, const char *operation, const char *item);
bool bll_toarg(lua_State* L, char* buf, int i, bool err);
int bll_pcall(lua_State* L, int nargs, int nret);
void bll_printError(lua_State* L, const char* operation, const char* item);
extern lua_State *gL;
extern lua_State* gL;
#endif

View File

@@ -8,8 +8,8 @@
#include "lauxlib.h"
#include "lua.h"
#include "luainterp.hpp"
int bll_TsCall(lua_State *L, const char *oname, const char *fname, int argc,
int ofs) {
int bll_TsCall(lua_State* L, const char* oname, const char* fname, int argc, int ofs) {
ADDR obj = (ADDR)NULL;
if (oname) {
obj = BlObject(oname);
@@ -22,15 +22,15 @@ int bll_TsCall(lua_State *L, const char *oname, const char *fname, int argc,
return luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
}
char *argv[BLL_ARG_COUNT];
char* argv[BLL_ARG_COUNT];
for (int i = 0; i < argc; i++) {
char *argbuf = bll_arg_buffer[i];
char* argbuf = bll_arg_buffer[i];
argv[i] = argbuf;
bll_toarg(L, argbuf, i + ofs + 1, true);
}
// /:^| /
const char *res;
const char* res;
if (obj) {
switch (argc) {
case 0:
@@ -55,71 +55,65 @@ int bll_TsCall(lua_State *L, const char *oname, const char *fname, int argc,
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4]);
break;
case 7:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5]);
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
break;
case 8:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6]);
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
break;
case 9:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7]);
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
break;
case 10:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8]);
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
break;
case 11:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
break;
case 12:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10]);
break;
case 13:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11]);
break;
case 14:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12]);
break;
case 15:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13]);
break;
case 16:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13], argv[14]);
break;
case 17:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15]);
break;
case 18:
res =
BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
break;
case 19:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15],
argv[16], argv[17]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
break;
case 20:
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15],
argv[16], argv[17], argv[18]);
res = BlCallObj(
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]);
break;
default:
res = "";
@@ -149,64 +143,60 @@ int bll_TsCall(lua_State *L, const char *oname, const char *fname, int argc,
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
break;
case 7:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6]);
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
break;
case 8:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7]);
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
break;
case 9:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8]);
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
break;
case 10:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9]);
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
break;
case 11:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
break;
case 12:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11]);
break;
case 13:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12]);
break;
case 14:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13]);
break;
case 15:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13], argv[14]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14]);
break;
case 16:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13], argv[14], argv[15]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15]);
break;
case 17:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13], argv[14], argv[15], argv[16]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
break;
case 18:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
break;
case 19:
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], argv[8], argv[9], argv[10], argv[11],
argv[12], argv[13], argv[14], argv[15], argv[16], argv[17],
argv[18]);
res = BlCall(
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]);
break;
default:
res = "";
@@ -218,57 +208,58 @@ int bll_TsCall(lua_State *L, const char *oname, const char *fname, int argc,
return 1;
}
// Lua lib function: ts.call
int bll_lua_tscall(lua_State *L) {
int bll_lua_tscall(lua_State* L) {
int argc = lua_gettop(L) - 1; // number of arguments after function name
if (argc < 0)
return luaL_error(L, "_bllua_ts.call: Must provide a function name");
const char *fname = luaL_checkstring(L, 1);
const char* fname = luaL_checkstring(L, 1);
return bll_TsCall(L, NULL, fname, argc, 1);
}
// Lua lib function: ts.callobj
int bll_lua_tscallobj(lua_State *L) {
int argc =
lua_gettop(L) - 2; // number of arguments after function name and object?
if (argc < 0)
return luaL_error(
L, "_bllua_ts.callobj: Must provide an object and function name");
const char *oname = luaL_checkstring(L, 1);
const char *fname = luaL_checkstring(L, 2);
// Lua lib function: ts.callobj
int bll_lua_tscallobj(lua_State* L) {
int argc = lua_gettop(L) - 2; // number of arguments after function name and object?
if (argc < 0)
return luaL_error(L, "_bllua_ts.callobj: Must provide an object and function name");
const char* oname = luaL_checkstring(L, 1);
const char* fname = luaL_checkstring(L, 2);
return bll_TsCall(L, oname, fname, argc, 2);
}
// Lua lib function: ts.getvar
int bll_lua_tsgetvar(lua_State *L) {
const char *vname = luaL_checkstring(L, 1);
int bll_lua_tsgetvar(lua_State* L) {
const char* vname = luaL_checkstring(L, 1);
const char *var = BlGetVar(vname);
const char* var = BlGetVar(vname);
lua_pushstring(L, var);
return 1;
}
// Lua lib function: ts.getfield
int bll_lua_tsgetfield(lua_State *L) {
const char *oname = luaL_checkstring(L, 1);
const char *vname = luaL_checkstring(L, 2);
int bll_lua_tsgetfield(lua_State* L) {
const char* oname = luaL_checkstring(L, 1);
const char* vname = luaL_checkstring(L, 2);
ADDR obj = BlObject(oname);
if (!obj) {
return luaL_error(L, "_bllua_ts.getfield: Object not found");
}
const char *val = BlGetField(obj, vname, NULL);
const char* val = BlGetField(obj, vname, NULL);
lua_pushstring(L, val);
return 1;
}
// Lua lib function: ts.setfield
int bll_lua_tssetfield(lua_State *L) {
const char *oname = luaL_checkstring(L, 1);
const char *vname = luaL_checkstring(L, 2);
const char *val = luaL_checkstring(L, 3);
int bll_lua_tssetfield(lua_State* L) {
const char* oname = luaL_checkstring(L, 1);
const char* vname = luaL_checkstring(L, 2);
const char* val = luaL_checkstring(L, 3);
ADDR obj = BlObject(oname);
if (!obj) {
return luaL_error(L, "_bllua_ts.setfield: Object not found");
@@ -279,17 +270,17 @@ int bll_lua_tssetfield(lua_State *L) {
}
// Lua lib function: ts.eval
int bll_lua_tseval(lua_State *L) {
const char *str = luaL_checkstring(L, 1);
const char *res = BlEval(str);
int bll_lua_tseval(lua_State* L) {
const char* str = luaL_checkstring(L, 1);
const char* res = BlEval(str);
lua_pushstring(L, res);
return 1;
}
// Lua lib function: ts.echo
// Print to BL console - used in Lua print implementation
int bll_lua_tsecho(lua_State *L) {
const char *str = luaL_checkstring(L, 1);
int bll_lua_tsecho(lua_State* L) {
const char* str = luaL_checkstring(L, 1);
BlPrintf("%s", str);
return 0;
}
@@ -300,4 +291,5 @@ const luaL_Reg bll_lua_reg[] = {
{"setfield", bll_lua_tssetfield}, {"eval", bll_lua_tseval},
{"echo", bll_lua_tsecho}, {NULL, NULL},
};
void llibbl_init(lua_State *L) { luaL_register(L, "_bllua_ts", bll_lua_reg); }
void llibbl_init(lua_State* L) { luaL_register(L, "_bllua_ts", bll_lua_reg); }

View File

@@ -4,7 +4,8 @@
#include "BlFuncs.hpp"
#include "BlHooks.hpp"
#include "luainterp.hpp"
bool bll_LuaCall(const char *fname, int argc, const char *argv[]) {
bool bll_LuaCall(const char* fname, int argc, const char* argv[]) {
lua_getglobal(gL, fname);
for (int i = 0; i < argc; i++) {
lua_pushstring(gL, argv[i]);
@@ -17,7 +18,7 @@ bool bll_LuaCall(const char *fname, int argc, const char *argv[]) {
}
// TS lib function: luacall
const char *bll_ts_luacall(ADDR obj, int argc, const char *argv[]) {
const char* bll_ts_luacall(ADDR obj, int argc, const char* argv[]) {
if (argc < 2)
return "";
@@ -25,7 +26,7 @@ const char *bll_ts_luacall(ADDR obj, int argc, const char *argv[]) {
return "";
}
char *retbuf = BlReturnBuffer(BLL_ARG_MAX);
char* retbuf = BlReturnBuffer(BLL_ARG_MAX);
bll_toarg(gL, retbuf, -1, false); // provide returned value to ts
lua_pop(gL, 1); // pop returned value
return retbuf;

View File

@@ -42,4 +42,26 @@ package _bllua_objectDeletionHook {
};
activatePackage(_bllua_objectDeletionHook);
// 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 libbl-support.cs");

View File

@@ -2,23 +2,39 @@
-- Main lua-side functionality of bllua,
-- provided through the global table 'bl.'
-- todo: set
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-Z0-9_]+$')
return type(name) == 'string' and name:find('^[a-zA-Z_][a-zA-Z0-9_]*$')
end
local function isValidFuncNameNs(name)
return type(name) == 'string' and (
@@ -76,23 +92,23 @@ for k, v in pairs(tsTypesByName) do
tsTypesByNum[v] = k
end
-- Type conversion
-- Type conversion from Lua to TS
local toTsObject
-- Convert a string from TS into a boolean
-- Note: Nonempty nonnumeric strings evaluate to 1, unlike in TS
local function tsBool(v) return v ~= '' and v ~= '0' end
-- Convert a Lua var into a TS string, or error if not possible
local function valToTs(val)
if val == nil then -- nil -> ''
if val == nil then -- nil -> ''
return ''
elseif type(val) == 'boolean' then -- bool -> 0 or 1
return val and '1' or '0'
elseif type(val) == 'number' then -- number
elseif type(val) == 'number' then -- number
return tostring(val)
elseif type(val) == 'string' then -- string
elseif type(val) == 'string' then -- string
return val
elseif type(val) == 'table' then
if val._tsObjectId then -- object -> object id
if val._tsObjectId then -- object -> object id
return tostring(val._tsObjectId)
elseif isTsVector(val) then -- vector - > 3 numbers
return table.concat(val, ' ')
@@ -100,36 +116,84 @@ local function valToTs(val)
-- box - > 6 numbers
return table.concat(val[1], ' ') .. ' ' .. table.concat(val[2], ' ')
else
error('valToTs: could not convert table', 3)
error('valToTs: cannot pass Lua tables to TorqueScript.', 3)
end
else
error('valToTs: could not convert ' .. type(val), 3)
error('valToTs: could not convert value to TorqueScript: ' .. tostring(val), 3)
end
end
-- Type conversion from TS to Lua
local fromTsForceTypes = {
['boolean'] = tsBool,
['object'] = function(val) toTsObject(val) end, -- toTsObject not defined yet
['string'] = tostring,
['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 convertValFromTs(val, typ)
return fromTsForceTypes[typ](val) or
error('valFromTs: invalid force type ' .. typ, 4)
local function forceValFromTs(val, typ)
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]+)$')
if xS then
return vector { tonumber(xS), tonumber(yS), tonumber(zS) }
else
return nil
end
end
local function boxFromTs(val)
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
if x1S then
return {
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
else
return nil
end
end
local function multinumericFromTs(val)
local tsNumPat = '%-?[0-9]+%.?[0-9]*e?[0-9]*'
if val:find('^' .. tsNumPat) then
local nums = {}
for _, part in ipairs(val:split(' ')) do
if part:find('^' .. tsNumPat .. '$') then
table.insert(nums, tonumber(part))
else
return nil
end
end
if #nums == 2 or #nums == 3 then
return vector(nums)
elseif #nums == 6 then -- box
return {
vector { nums[1], nums[2], nums[3] },
vector { nums[4], nums[5], nums[6] } }
elseif #nums == 7 then -- axis
return nil --return matrix(nums)
else
return nil
end
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
name = name:lower()
if bl._forceType[name] then
return convertValFromTs(val, bl._forceType[name])
return forceValFromTs(val, bl._forceType[name])
end
end
if name2 then
name2 = name2:lower()
if bl._forceType[name2] then
return convertValFromTs(val, bl._forceType[name2])
return forceValFromTs(val, bl._forceType[name2])
end
end
-- '' -> nil
@@ -137,30 +201,29 @@ local function valFromTs(val, name, name2) -- todo: ensure name and name2 are al
-- number
local num = tonumber(val)
if num then return num end
-- vector
local xS, yS, zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
if xS then return vector { tonumber(xS), tonumber(yS), tonumber(zS) } end
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
-- box (2 vectors)
if x1S then
return {
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
-- vector, box, or axis->matrix
local vec = multinumericFromTs(val)
if vec then return vec end
-- net string
if val:sub(1, 1) == '\001' 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_]+)(::.+)$')
@@ -195,13 +258,33 @@ setForceType = function(ftname, typ)
end
bl.type = setForceType
-- Type conversion TS->Lua backwards, convert back to string
local function numFromTsTostring(val)
-- todo: as-good-as-possible scientific notation for numbers
return tostring(val)
end
local function valFromTsTostring(val)
if type(val) == 'string' then
return val
elseif type(val) == 'number' then
return numFromTsTostring(val)
elseif type(val) == 'table' then
if val.__is_vector then
local strs = {}
for i = 1, #val do strs[i] = numFromTsTostring(val[i]) end
return table.concat(strs, ' ')
elseif val.__is_matrix then
-- todo: matrix back to axis-angle string
error('bl.string: matrix not yet supported', 3)
end
end
error('bl.string: cannot convert \'' .. type(val) .. '\'', 3)
end
-- Value detection
-- Getting info from TS about functions and objects
local function isTsObject(t)
return type(t) == 'table' and t._tsObjectId ~= nil
end
local function tsIsObject(name) return tsBool(_bllua_ts.call('isObject', name)) end
local function tsIsFunction(name) return tsBool(_bllua_ts.call('isFunction', name)) end
local function tsIsFunctionNs(ns, name) return tsBool(_bllua_ts.call('isFunction', ns, name)) end
@@ -213,30 +296,33 @@ local function tsIsFunctionNsname(nsname)
return tsIsFunction(nsname)
end
end
-- sanity check to make sure objects that don't isObject are always marked as ._deleted
-- can be removed later
local function assertTsObjectExists(obj)
local is = tsIsObject(obj._tsObjectId)
if not is then
print('Warning: TS object :exists or isobject from lua but no longer exists')
end
return is
end
function bl.isObject(obj)
if isTsObject(obj) then
obj = obj._tsObjectId
elseif type(obj) == 'number' then
obj = tostring(obj)
elseif type(obj) ~= 'string' then
if type(obj) == 'number' then -- object id
return tsIsObject(tostring(obj))
elseif type(obj) == 'string' then -- object name
return tsIsObject(obj)
elseif isTsObject(obj) then -- lua object
if obj._deleted then
return false
else
return assertTsObjectExists(obj)
end
else
error('bl.isObject: argument #1: expected torque object, number, or string', 2)
end
return tsIsObject(obj)
end
function bl.isFunction(a1, a2)
if type(a1) ~= 'string' then
error('bl.isFunction: argument #1: expected string', 2)
end
if a2 then
if type(a2) ~= 'string' then
error('bl.isFunction: argument #2: expected string', 2)
end
return tsIsFunctionNs(a1, a2)
else
return tsIsFunction(a1)
end
function bl.isFunction(name)
return tsIsFunctionNsname(name)
end
-- Torque object pseudo-class
@@ -328,17 +414,20 @@ 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
@@ -376,7 +465,8 @@ local tsObjectMeta = {
-- Display a nice info string
__tostring = function(t)
return 'torque:' .. t._tsNamespace .. ':' .. t._tsObjectId ..
(t._tsName ~= '' and ('(' .. t._tsName .. ')') or '')
(t._tsName ~= '' and ('(' .. t._tsName .. ')') or '') ..
(t._deleted and '(deleted)' or '')
end,
-- #object
-- If the object has a getCount method, return its count
@@ -412,7 +502,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
@@ -469,8 +560,9 @@ local tsObjectMeta = {
end
if t._deleted then
return false
else
return assertTsObjectExists(t)
end
return tsIsObject(t._tsObjectId)
end,
}
-- Weak-values table for caching Torque object references
@@ -504,7 +596,7 @@ toTsObject = function(idiS)
idiS = idiS:lower()
if bl._objectsWeak[idiS] then return bl._objectsWeak[idiS] end
if not tsBool(_bllua_ts.call('isObject', idiS)) then
if not tsIsObject(idiS) then
--error('toTsObject: object \''..idiS..'\' does not exist', 2) end
return nil
end
@@ -527,14 +619,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
@@ -542,9 +633,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
@@ -570,14 +661,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,
@@ -597,11 +690,18 @@ function bl.call(func, ...)
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 = { ... }
return name .. table.concat(rest, '_')
end
function bl.boolean(val)
@@ -622,21 +722,77 @@ function bl.object(id)
end
end
function bl.array(name, ...)
local rest = { ... }
return name .. table.concat(rest, '_')
function bl.string(val)
return valFromTsTostring(val)
end
function _bllua_call(fnameS, ...)
local args = arglistFromTs('lua:' .. fnameS:lower(), { ... }) -- todo: allow this though bl.type
if not _G[fnameS] then
error('luacall: no global lua function named \'' .. fnameS .. '\'')
-- Lua calling from TS
local luaLookup
luaLookup = function(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 tbl[first] == nil then
if set then
tbl[first] = {}
else
return nil
end
end
return luaLookup(tbl[first], rest, set, val)
elseif name:find(':') then
local first, rest = name:match('^([^%.:]+):(.*)$')
if rest:find('[%.:]') then
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 tbl[first][rest] == nil then
error('luacall: no method named \'' .. rest .. '\'', 3)
end
return function(...)
tbl[first][rest](tbl[first], ...)
end
else
if set then
tbl[name] = val
else
return tbl[name]
end
end
-- todo: library fields and object methods
local res = _G[fnameS](unpack(args))
end
-- Todo: similar deep access for luaget and luaset
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 \'' .. fname .. '\'', 2)
end
local res = func(unpack(args))
return valToTs(res)
end
function _bllua_getvar(vname)
return valToTs(luaLookup(_G, vname))
end
function _bllua_setvar(vname, valS)
return valToTs(luaLookup(_G, vname, true, valFromTs(valS, vname))) -- todo: separate lua from ts var names?
end
function _bllua_eval(code) return loadstring(code)() end
function _bllua_exec(fn) return dofile(fn, 2) end
-- bl.schedule: Use TS's schedule function to schedule lua calls
-- bl.schedule(time, function, args...)
bl._scheduleTable = bl._scheduleTable or {}
@@ -688,9 +844,8 @@ local function addCmd(cmd, func)
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()
@@ -710,8 +865,9 @@ function bl.commandToServer(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
@@ -741,10 +897,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, { ... })
@@ -759,7 +911,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
@@ -779,13 +931,13 @@ 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 ''
@@ -794,10 +946,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)
@@ -829,10 +982,10 @@ 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
@@ -861,10 +1014,13 @@ function bl.unhook(pkg, name, time)
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
@@ -923,7 +1079,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
@@ -975,7 +1131,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)
@@ -1023,9 +1179,9 @@ local function parseTsDecl(decl)
if decl:find(' ') then -- class ...
local cl, rest = decl:match('^([^ ]+) ([^ ]+)$')
class = cl
if rest:find(':') then -- class name:inherit
if rest:find(':') then -- class name:inherit
name, inherit = rest:match('^([^:]*):([^:]+)$')
if not name then class = nil end -- error
if not name then class = nil end -- error
if name == '' then name = nil end -- class :inherit
else
name = rest

View File

@@ -93,11 +93,15 @@ local allowed_zip_dirs = tflip {
local function io_open_absolute(fn, mode)
-- if file exists, use original mode
local res, err = _bllua_io_open(fn, mode)
if res then return res end
if res then
return res
elseif err and not err:find('No such file or directory$') then
return nil, err
end
-- otherwise, if TS sees file but Lua doesn't, it must be in a zip, so use TS reader
local dir = fn:match('^[^/]+')
if not allowed_zip_dirs[dir:lower()] then return nil, 'File is not in one of the allowed directories' end
if not allowed_zip_dirs[dir:lower()] then return nil, 'Zip is not in one of the allowed directories' end
local exist = _bllua_ts.call('isFile', fn) == '1'
if not exist then return nil, err end
@@ -135,8 +139,8 @@ end
---@diagnostic disable-next-line: duplicate-set-field
function io.lines(fn)
local fi, err, fn2 = io.open(fn, 'r', 2)
if not fi then error('Error opening file \'' .. tostring(fn2) .. '\': ' .. tostring(err), 2) end
local fi, err, fn2 = io.open(fn, nil, 2)
if not fi then error('Error opening file \'' .. fn2 .. '\': ' .. err, 2) end
return fi:lines()
end
@@ -156,7 +160,7 @@ function dofile(fn, errn)
errn = errn or 1
local fi, err, fn2 = io.open(fn, 'r', errn + 1)
if not fi then error('Error executing file \'' .. tostring(fn2) .. '\': ' .. tostring(err), errn + 1) end
if not fi then error('Error executing file \'' .. fn2 .. '\': ' .. err, errn + 1) end
print('Executing ' .. fn2)
local text = fi:read('*a')
@@ -204,15 +208,6 @@ function require(mod)
return _bllua_requiresecure(mod)
end
-- Exposure to TS
function _bllua_getvar(name) return _G[name] end
function _bllua_setvar(name, val) _G[name] = val end
function _bllua_eval(code) return loadstring(code)() end
function _bllua_exec(fn) return dofile(fn, 2) end
local function isValidCode(code)
local f, e = loadstring(code)
return f ~= nil

View File

@@ -49,26 +49,4 @@ function _bllua_set_var(%name, %val) {
return "";
}
// 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");

6
src/util/matrix.lua Normal file
View File

@@ -0,0 +1,6 @@
-- todo
-- Matrix class with math operators
print(' Executed matrix.lua')

View File

@@ -4,7 +4,7 @@
-- Table / List
-- Whether a table contains no keys
function table.empty(t)
return next(t) ~= nil
return next(t) == nil
end
-- Apply a function to each key in a table
@@ -13,8 +13,19 @@ function table.map(f, ...)
local u = {}
for k, _ in pairs(ts[1]) do
local args = {}
for j = 1, #ts do args[j] = ts[j][i] end
u[i] = f(unpack(args))
for j = 1, #ts do args[j] = ts[j][k] end
u[k] = f(unpack(args))
end
return u
end
function table.mapk(f, ...)
local ts = { ... }
local u = {}
for k, _ in pairs(ts[1]) do
local args = {}
for j = 1, #ts do args[j] = ts[j][k] end
u[k] = f(k, unpack(args))
end
return u
end
@@ -30,6 +41,17 @@ function table.map_list(f, ...)
return u
end
function table.mapi_list(f, ...)
local ts = { ... }
local u = {}
for i = 1, #ts[1] do
local args = {}
for j = 1, #ts do args[j] = ts[j][i] end
u[i] = f(i, unpack(args))
end
return u
end
-- Swap keys/values
function table.swap(t)
local u = {}
@@ -193,7 +215,7 @@ valueToString = function(v, tabLevel, seen)
return tostring(v)
else
--error('table.tostring: table contains a '..t..' value, cannot serialize')
return 'nil --[[ cannot serialize ' .. t .. ': ' .. tostring(v) .. ' ]]'
return 'nil --[[ ' .. tostring(v) .. ' ]]'
end
end
function table.tostring(t)
@@ -372,3 +394,5 @@ end
function math.clamp(v, n, x)
return math.min(x, math.max(v, n))
end
print(' Executed std.lua')

View File

@@ -235,4 +235,7 @@ vector_new = function(vi)
end
vector = vector_new
print(' Executed vector.lua')
return vector_new