WIP: Auios' version - Do not merge. Only here for comparison #9
42
.clang-format
Normal file
42
.clang-format
Normal file
@@ -0,0 +1,42 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Include sorting and grouping
|
||||
SortIncludes: CaseSensitive
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '<Windows\.h>'
|
||||
Priority: 1
|
||||
- Regex: '<Psapi\.h>'
|
||||
Priority: 2
|
||||
- Regex: '"BlHooks\\.hpp"'
|
||||
Priority: 3
|
||||
- Regex: '"BlFuncs\\.hpp"'
|
||||
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
|
||||
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
.*
|
||||
!.gitignore
|
||||
build/
|
||||
.cache/
|
||||
|
||||
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"Lua.diagnostics.globals": [
|
||||
"_bllua_ts",
|
||||
"_bllua_requiresecure",
|
||||
"_bllua_on_unload"
|
||||
],
|
||||
"Lua.runtime.version": "Lua 5.1",
|
||||
"Lua.diagnostics.disable": ["lowercase-global", "undefined-global"],
|
||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||
"C_Cpp.default.compilerPath": "C:/msys64/mingw32/bin/g++.exe"
|
||||
}
|
||||
BIN
BlockLua.dll
BIN
BlockLua.dll
Binary file not shown.
56
CMakeLists.txt
Normal file
56
CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(BlockLua CXX)
|
||||
|
||||
# Export compile_commands.json for VSCode IntelliSense
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# 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 build options to mirror build.bat
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Werror
|
||||
-m32
|
||||
-static-libgcc
|
||||
-static-libstdc++
|
||||
)
|
||||
|
||||
# Include paths
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/inc/tsfuncs
|
||||
${CMAKE_SOURCE_DIR}/inc/lua
|
||||
)
|
||||
|
||||
# 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 build.bat
|
||||
set_target_properties(BlockLua PROPERTIES OUTPUT_NAME "BlockLua")
|
||||
# Linker flags and libraries
|
||||
if(MSVC)
|
||||
# Not expected with mingw, but keep placeholder
|
||||
else()
|
||||
target_link_libraries(BlockLua PRIVATE psapi lua5.1)
|
||||
endif()
|
||||
|
||||
# Unsafe DLL (with BLLUA_UNSAFE definition)
|
||||
add_library(BlockLuaUnsafe SHARED src/bllua4.cpp)
|
||||
set_target_properties(BlockLuaUnsafe PROPERTIES OUTPUT_NAME "BlockLua-Unsafe")
|
||||
|
||||
target_compile_definitions(BlockLuaUnsafe PRIVATE BLLUA_UNSAFE)
|
||||
|
||||
if(MSVC)
|
||||
# Not expected with mingw, but keep placeholder
|
||||
else()
|
||||
target_link_libraries(BlockLuaUnsafe PRIVATE psapi lua5.1)
|
||||
endif()
|
||||
27
build.bat
Normal file
27
build.bat
Normal file
@@ -0,0 +1,27 @@
|
||||
@echo off
|
||||
cd /d %~dp0
|
||||
|
||||
REM Ensure MinGW32 toolchain is first in PATH
|
||||
set "PATH=C:\msys64\mingw32\bin;%PATH%"
|
||||
|
||||
REM Configure CMake (generate into build/)
|
||||
cmake -S . -B build -G "MinGW Makefiles"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
REM Build (Release by default)
|
||||
cmake --build build --config Release -j
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
echo.
|
||||
echo Build completed.
|
||||
echo Outputs in .\build :
|
||||
echo - BlockLua.dll
|
||||
|
||||
echo - BlockLua-Unsafe.dll
|
||||
|
||||
exit /b 0
|
||||
|
||||
:error
|
||||
echo.
|
||||
echo Build failed. See errors above.
|
||||
exit /b 1
|
||||
52
compiling.md
Normal file
52
compiling.md
Normal file
@@ -0,0 +1,52 @@
|
||||
## Compiling on Windows with MSYS2 (32-bit)
|
||||
|
||||
Follow these steps to build `BlockLua.dll` for 32-bit Windows using MSYS2's MinGW-w64 i686 toolchain.
|
||||
|
||||
### 1) Install MSYS2
|
||||
|
||||
- Download and install MSYS2 from `https://www.msys2.org/`.
|
||||
- After installing, open the "MSYS2 MSYS" terminal once and update the package database if prompted.
|
||||
|
||||
### 2) Install required packages (i686 / 32-bit)
|
||||
|
||||
Run this in the "MSYS2 MSYS" or "MSYS2 MinGW 32-bit" terminal:
|
||||
|
||||
```bash
|
||||
pacman -Sy --needed mingw-w64-i686-toolchain mingw-w64-i686-binutils mingw-w64-i686-lua51
|
||||
```
|
||||
|
||||
What these packages are for:
|
||||
|
||||
- mingw-w64-i686-toolchain: 32-bit C/C++ compiler suite (g++, libstdc++, runtime libs) to build Windows binaries.
|
||||
- mingw-w64-i686-binutils: Linker and binary utilities (ld, as, objdump) used by the compiler and for optional inspection.
|
||||
- mingw-w64-i686-lua51: Lua 5.1 development files for 32-bit (import library). We use its import library to link; at runtime you can use the provided `lua5.1.dll`.
|
||||
|
||||
### 3) Build (PowerShell, recommended)
|
||||
|
||||
- Open PowerShell in the repo root.
|
||||
- Run the script:
|
||||
|
||||
```powershell
|
||||
build.bat
|
||||
```
|
||||
|
||||
What the script does:
|
||||
|
||||
- Temporarily prepends `C:\\msys64\\mingw32\\bin` to PATH so the 32-bit toolchain is used.
|
||||
- Compiles the project with `-m32` and links against `lua5.1`.
|
||||
- Produces `build\BlockLua.dll` and `build\BlockLua-Unsafe.dll`.
|
||||
|
||||
### 4) Optional: Verify 32-bit output
|
||||
|
||||
If you installed binutils, you can check the architecture:
|
||||
|
||||
```powershell
|
||||
objdump -f build\BlockLua.dll | Select-String i386
|
||||
```
|
||||
|
||||
You should see `architecture: i386` in the output.
|
||||
|
||||
### Notes
|
||||
|
||||
- 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`).
|
||||
@@ -4,93 +4,75 @@
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
/* extra error code for `luaL_load' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
#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)
|
||||
#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);
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
@@ -98,31 +80,27 @@ 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_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)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
#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)))
|
||||
#define luaL_optint(L, n, d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
#define luaL_checklong(L, n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L, n, d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
#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_getmetatable(L, n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(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_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
|
||||
#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))
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
@@ -130,31 +108,27 @@ LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef struct luaL_Buffer {
|
||||
char *p; /* current position in buffer */
|
||||
int lvl; /* number of strings in the stack (level) */
|
||||
lua_State *L;
|
||||
char* p; /* current position in buffer */
|
||||
int lvl; /* number of strings in the stack (level) */
|
||||
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_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);
|
||||
#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);
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
424
inc/lua/lua.h
424
inc/lua/lua.h
@@ -5,88 +5,75 @@
|
||||
** See Copyright Notice at the end of this file
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lua_h
|
||||
#define lua_h
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#include "luaconf.h"
|
||||
|
||||
|
||||
#define LUA_VERSION "Lua 5.1"
|
||||
#define LUA_RELEASE "Lua 5.1.4"
|
||||
#define LUA_VERSION_NUM 501
|
||||
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
||||
|
||||
#define LUA_VERSION "Lua 5.1"
|
||||
#define LUA_RELEASE "Lua 5.1.4"
|
||||
#define LUA_VERSION_NUM 501
|
||||
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
||||
|
||||
/* mark for precompiled code (`<esc>Lua') */
|
||||
#define LUA_SIGNATURE "\033Lua"
|
||||
#define LUA_SIGNATURE "\033Lua"
|
||||
|
||||
/* option for multiple returns in `lua_pcall' and `lua_call' */
|
||||
#define LUA_MULTRET (-1)
|
||||
|
||||
#define LUA_MULTRET (-1)
|
||||
|
||||
/*
|
||||
** pseudo-indices
|
||||
*/
|
||||
#define LUA_REGISTRYINDEX (-10000)
|
||||
#define LUA_ENVIRONINDEX (-10001)
|
||||
#define LUA_GLOBALSINDEX (-10002)
|
||||
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
|
||||
|
||||
#define LUA_REGISTRYINDEX (-10000)
|
||||
#define LUA_ENVIRONINDEX (-10001)
|
||||
#define LUA_GLOBALSINDEX (-10002)
|
||||
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX - (i))
|
||||
|
||||
/* thread status */
|
||||
#define LUA_OK 0
|
||||
#define LUA_YIELD 1
|
||||
#define LUA_ERRRUN 2
|
||||
#define LUA_ERRSYNTAX 3
|
||||
#define LUA_ERRMEM 4
|
||||
#define LUA_ERRERR 5
|
||||
|
||||
#define LUA_OK 0
|
||||
#define LUA_YIELD 1
|
||||
#define LUA_ERRRUN 2
|
||||
#define LUA_ERRSYNTAX 3
|
||||
#define LUA_ERRMEM 4
|
||||
#define LUA_ERRERR 5
|
||||
|
||||
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 int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
|
||||
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);
|
||||
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
#define LUA_TNONE (-1)
|
||||
|
||||
#define LUA_TNIL 0
|
||||
#define LUA_TBOOLEAN 1
|
||||
#define LUA_TLIGHTUSERDATA 2
|
||||
#define LUA_TNUMBER 3
|
||||
#define LUA_TSTRING 4
|
||||
#define LUA_TTABLE 5
|
||||
#define LUA_TFUNCTION 6
|
||||
#define LUA_TUSERDATA 7
|
||||
#define LUA_TTHREAD 8
|
||||
|
||||
#define LUA_TNONE (-1)
|
||||
|
||||
#define LUA_TNIL 0
|
||||
#define LUA_TBOOLEAN 1
|
||||
#define LUA_TLIGHTUSERDATA 2
|
||||
#define LUA_TNUMBER 3
|
||||
#define LUA_TSTRING 4
|
||||
#define LUA_TTABLE 5
|
||||
#define LUA_TFUNCTION 6
|
||||
#define LUA_TUSERDATA 7
|
||||
#define LUA_TTHREAD 8
|
||||
|
||||
/* minimum Lua stack available to a C function */
|
||||
#define LUA_MINSTACK 20
|
||||
|
||||
#define LUA_MINSTACK 20
|
||||
|
||||
/*
|
||||
** generic extra include file
|
||||
@@ -95,157 +82,141 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
#include LUA_USER_H
|
||||
#endif
|
||||
|
||||
|
||||
/* type of numbers in Lua */
|
||||
typedef LUA_NUMBER lua_Number;
|
||||
|
||||
|
||||
/* type for integer functions */
|
||||
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_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||
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);
|
||||
|
||||
/*
|
||||
** 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 void (lua_xmove) (lua_State *from, lua_State *to, int n);
|
||||
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);
|
||||
|
||||
/*
|
||||
** 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 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 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);
|
||||
|
||||
/*
|
||||
** 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 int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
|
||||
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);
|
||||
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
|
||||
#define LUA_GCSTOP 0
|
||||
#define LUA_GCRESTART 1
|
||||
#define LUA_GCCOLLECT 2
|
||||
#define LUA_GCCOUNT 3
|
||||
#define LUA_GCCOUNTB 4
|
||||
#define LUA_GCSTEP 5
|
||||
#define LUA_GCSETPAUSE 6
|
||||
#define LUA_GCSETSTEPMUL 7
|
||||
#define LUA_GCISRUNNING 9
|
||||
|
||||
LUA_API int (lua_gc) (lua_State *L, int what, int data);
|
||||
#define LUA_GCSTOP 0
|
||||
#define LUA_GCRESTART 1
|
||||
#define LUA_GCCOLLECT 2
|
||||
#define LUA_GCCOUNT 3
|
||||
#define LUA_GCCOUNTB 4
|
||||
#define LUA_GCSTEP 5
|
||||
#define LUA_GCSETPAUSE 6
|
||||
#define LUA_GCSETSTEPMUL 7
|
||||
#define LUA_GCISRUNNING 9
|
||||
|
||||
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 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 int(lua_next)(lua_State* L, int idx);
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
@@ -253,52 +224,47 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
||||
#define lua_pop(L, n) lua_settop(L, -(n) - 1)
|
||||
|
||||
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
||||
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
||||
|
||||
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
||||
#define lua_register(L, n, f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
||||
|
||||
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
|
||||
#define lua_pushcfunction(L, f) lua_pushcclosure(L, (f), 0)
|
||||
|
||||
#define lua_strlen(L,i) lua_objlen(L, (i))
|
||||
#define lua_strlen(L, i) lua_objlen(L, (i))
|
||||
|
||||
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
||||
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
|
||||
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
|
||||
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
|
||||
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
|
||||
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
|
||||
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
|
||||
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
||||
#define lua_isfunction(L, n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
||||
#define lua_istable(L, n) (lua_type(L, (n)) == LUA_TTABLE)
|
||||
#define lua_islightuserdata(L, n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
|
||||
#define lua_isnil(L, n) (lua_type(L, (n)) == LUA_TNIL)
|
||||
#define lua_isboolean(L, n) (lua_type(L, (n)) == LUA_TBOOLEAN)
|
||||
#define lua_isthread(L, n) (lua_type(L, (n)) == LUA_TTHREAD)
|
||||
#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_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
|
||||
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
|
||||
|
||||
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
|
||||
#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))
|
||||
|
||||
#define lua_tostring(L, i) lua_tolstring(L, (i), NULL)
|
||||
|
||||
/*
|
||||
** compatibility macros and functions
|
||||
*/
|
||||
|
||||
#define lua_open() luaL_newstate()
|
||||
#define lua_open() luaL_newstate()
|
||||
|
||||
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
|
||||
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
|
||||
|
||||
#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
|
||||
|
||||
#define lua_Chunkreader lua_Reader
|
||||
#define lua_Chunkwriter lua_Writer
|
||||
#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
|
||||
|
||||
#define lua_Chunkreader lua_Reader
|
||||
#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);
|
||||
|
||||
/*
|
||||
** {======================================================================
|
||||
@@ -306,97 +272,89 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to);
|
||||
** =======================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** Event codes
|
||||
*/
|
||||
#define LUA_HOOKCALL 0
|
||||
#define LUA_HOOKRET 1
|
||||
#define LUA_HOOKLINE 2
|
||||
#define LUA_HOOKCOUNT 3
|
||||
#define LUA_HOOKCALL 0
|
||||
#define LUA_HOOKRET 1
|
||||
#define LUA_HOOKLINE 2
|
||||
#define LUA_HOOKCOUNT 3
|
||||
#define LUA_HOOKTAILRET 4
|
||||
|
||||
|
||||
/*
|
||||
** Event masks
|
||||
*/
|
||||
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||
#define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||
|
||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
||||
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||
#define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||
|
||||
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) */
|
||||
int currentline; /* (l) */
|
||||
int nups; /* (u) number of upvalues */
|
||||
int linedefined; /* (S) */
|
||||
int lastlinedefined; /* (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) */
|
||||
int lastlinedefined; /* (S) */
|
||||
char short_src[LUA_IDSIZE]; /* (S) */
|
||||
/* private part */
|
||||
int i_ci; /* active function */
|
||||
int i_ci; /* active function */
|
||||
};
|
||||
|
||||
/* }====================================================================== */
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// C++ wrapper for LuaJIT header files.
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
#include "lua.h"
|
||||
#include "luajit.h"
|
||||
#include "lualib.h"
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0501
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -18,135 +19,138 @@
|
||||
** In Windows, any exclamation mark ('!') in the path is replaced by the
|
||||
** path of the directory of the executable file of the current process.
|
||||
*/
|
||||
#define LUA_LDIR "!\\lua\\"
|
||||
#define LUA_CDIR "!\\"
|
||||
#define LUA_PATH_DEFAULT \
|
||||
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;"
|
||||
#define LUA_CPATH_DEFAULT \
|
||||
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
|
||||
#define LUA_LDIR "!\\lua\\"
|
||||
#define LUA_CDIR "!\\"
|
||||
#define LUA_PATH_DEFAULT ".\\?.lua;" LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;"
|
||||
#define LUA_CPATH_DEFAULT ".\\?.dll;" LUA_CDIR "?.dll;" LUA_CDIR "loadall.dll"
|
||||
#else
|
||||
/*
|
||||
** Note to distribution maintainers: do NOT patch the following lines!
|
||||
** Please read ../doc/install.html#distro and pass PREFIX=/usr instead.
|
||||
*/
|
||||
#ifndef LUA_MULTILIB
|
||||
#define LUA_MULTILIB "lib"
|
||||
#define LUA_MULTILIB "lib"
|
||||
#endif
|
||||
#ifndef LUA_LMULTILIB
|
||||
#define LUA_LMULTILIB "lib"
|
||||
#define LUA_LMULTILIB "lib"
|
||||
#endif
|
||||
#define LUA_LROOT "/usr/local"
|
||||
#define LUA_LUADIR "/lua/5.1/"
|
||||
#define LUA_LJDIR "/luajit-2.1.0-beta3/"
|
||||
#define LUA_LROOT "/usr/local"
|
||||
#define LUA_LUADIR "/lua/5.1/"
|
||||
#define LUA_LJDIR "/luajit-2.1.0-beta3/"
|
||||
|
||||
#ifdef LUA_ROOT
|
||||
#define LUA_JROOT LUA_ROOT
|
||||
#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR
|
||||
#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR
|
||||
#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua"
|
||||
#define LUA_RCPATH ";" LUA_RCDIR "?.so"
|
||||
#define LUA_JROOT LUA_ROOT
|
||||
#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR
|
||||
#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR
|
||||
#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua"
|
||||
#define LUA_RCPATH ";" LUA_RCDIR "?.so"
|
||||
#else
|
||||
#define LUA_JROOT LUA_LROOT
|
||||
#define LUA_JROOT LUA_LROOT
|
||||
#define LUA_RLPATH
|
||||
#define LUA_RCPATH
|
||||
#endif
|
||||
|
||||
#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua"
|
||||
#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR
|
||||
#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR
|
||||
#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua"
|
||||
#define LUA_LCPATH1 ";" LUA_LCDIR "?.so"
|
||||
#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so"
|
||||
#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua"
|
||||
#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR
|
||||
#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR
|
||||
#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua"
|
||||
#define LUA_LCPATH1 ";" LUA_LCDIR "?.so"
|
||||
#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so"
|
||||
|
||||
#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH
|
||||
#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2
|
||||
#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH
|
||||
#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2
|
||||
#endif
|
||||
|
||||
/* Environment variable names for path overrides and initialization code. */
|
||||
#define LUA_PATH "LUA_PATH"
|
||||
#define LUA_CPATH "LUA_CPATH"
|
||||
#define LUA_INIT "LUA_INIT"
|
||||
#define LUA_PATH "LUA_PATH"
|
||||
#define LUA_CPATH "LUA_CPATH"
|
||||
#define LUA_INIT "LUA_INIT"
|
||||
|
||||
/* Special file system characters. */
|
||||
#if defined(_WIN32)
|
||||
#define LUA_DIRSEP "\\"
|
||||
#define LUA_DIRSEP "\\"
|
||||
#else
|
||||
#define LUA_DIRSEP "/"
|
||||
#define LUA_DIRSEP "/"
|
||||
#endif
|
||||
#define LUA_PATHSEP ";"
|
||||
#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_PATHSEP ";"
|
||||
#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"
|
||||
|
||||
/* Quoting in error messages. */
|
||||
#define LUA_QL(x) "'" x "'"
|
||||
#define LUA_QS LUA_QL("%s")
|
||||
#define LUA_QL(x) "'" x "'"
|
||||
#define LUA_QS LUA_QL("%s")
|
||||
|
||||
/* Various tunables. */
|
||||
#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */
|
||||
#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */
|
||||
#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */
|
||||
#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */
|
||||
#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */
|
||||
#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */
|
||||
#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */
|
||||
#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */
|
||||
#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */
|
||||
#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */
|
||||
|
||||
/* Configuration for the frontend (the luajit executable). */
|
||||
#if defined(luajit_c)
|
||||
#define LUA_PROGNAME "luajit" /* Fallback frontend name. */
|
||||
#define LUA_PROMPT "> " /* Interactive prompt. */
|
||||
#define LUA_PROMPT2 ">> " /* Continuation prompt. */
|
||||
#define LUA_MAXINPUT 512 /* Max. input line length. */
|
||||
#define LUA_PROGNAME "luajit" /* Fallback frontend name. */
|
||||
#define LUA_PROMPT "> " /* Interactive prompt. */
|
||||
#define LUA_PROMPT2 ">> " /* Continuation prompt. */
|
||||
#define LUA_MAXINPUT 512 /* Max. input line length. */
|
||||
#endif
|
||||
|
||||
/* Note: changing the following defines breaks the Lua 5.1 ABI. */
|
||||
#define LUA_INTEGER ptrdiff_t
|
||||
#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */
|
||||
#define LUA_INTEGER ptrdiff_t
|
||||
#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */
|
||||
/*
|
||||
** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using
|
||||
** unreasonable amounts of stack space, but still retain ABI compatibility.
|
||||
** Blame Lua for depending on BUFSIZ in the ABI, blame **** for wrecking it.
|
||||
*/
|
||||
#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ)
|
||||
#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ)
|
||||
|
||||
/* The following defines are here only for compatibility with luaconf.h
|
||||
** from the standard Lua distribution. They must not be changed for LuaJIT.
|
||||
*/
|
||||
#define LUA_NUMBER_DOUBLE
|
||||
#define LUA_NUMBER double
|
||||
#define LUAI_UACNUMBER double
|
||||
#define LUA_NUMBER_SCAN "%lf"
|
||||
#define LUA_NUMBER_FMT "%.14g"
|
||||
#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n))
|
||||
#define LUAI_MAXNUMBER2STR 32
|
||||
#define LUA_INTFRMLEN "l"
|
||||
#define LUA_INTFRM_T long
|
||||
#define LUA_NUMBER double
|
||||
#define LUAI_UACNUMBER double
|
||||
#define LUA_NUMBER_SCAN "%lf"
|
||||
#define LUA_NUMBER_FMT "%.14g"
|
||||
#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n))
|
||||
#define LUAI_MAXNUMBER2STR 32
|
||||
#define LUA_INTFRMLEN "l"
|
||||
#define LUA_INTFRM_T long
|
||||
|
||||
/* Linkage of public API functions. */
|
||||
#if defined(LUA_BUILD_AS_DLL)
|
||||
#if defined(LUA_CORE) || defined(LUA_LIB)
|
||||
#define LUA_API __declspec(dllexport)
|
||||
#define LUA_API __declspec(dllexport)
|
||||
#else
|
||||
#define LUA_API __declspec(dllimport)
|
||||
#define LUA_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LUA_API extern
|
||||
#define LUA_API extern
|
||||
#endif
|
||||
|
||||
#define LUALIB_API LUA_API
|
||||
#define LUALIB_API LUA_API
|
||||
|
||||
/* Support for internal assertions. */
|
||||
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#ifdef LUA_USE_ASSERT
|
||||
#define lua_assert(x) assert(x)
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,48 +30,45 @@
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#define LUAJIT_VERSION "LuaJIT 2.1.0-beta3"
|
||||
#define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */
|
||||
#define LUAJIT_VERSION_SYM luaJIT_version_2_1_0_beta3
|
||||
#define LUAJIT_COPYRIGHT "Copyright (C) 2005-2017 Mike Pall"
|
||||
#define LUAJIT_URL "http://luajit.org/"
|
||||
#define LUAJIT_VERSION "LuaJIT 2.1.0-beta3"
|
||||
#define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */
|
||||
#define LUAJIT_VERSION_SYM luaJIT_version_2_1_0_beta3
|
||||
#define LUAJIT_COPYRIGHT "Copyright (C) 2005-2017 Mike Pall"
|
||||
#define LUAJIT_URL "http://luajit.org/"
|
||||
|
||||
/* Modes for luaJIT_setmode. */
|
||||
#define LUAJIT_MODE_MASK 0x00ff
|
||||
#define LUAJIT_MODE_MASK 0x00ff
|
||||
|
||||
enum {
|
||||
LUAJIT_MODE_ENGINE, /* Set mode for whole JIT engine. */
|
||||
LUAJIT_MODE_DEBUG, /* Set debug mode (idx = level). */
|
||||
LUAJIT_MODE_ENGINE, /* Set mode for whole JIT engine. */
|
||||
LUAJIT_MODE_DEBUG, /* Set debug mode (idx = level). */
|
||||
|
||||
LUAJIT_MODE_FUNC, /* Change mode for a function. */
|
||||
LUAJIT_MODE_ALLFUNC, /* Recurse into subroutine protos. */
|
||||
LUAJIT_MODE_ALLSUBFUNC, /* Change only the subroutines. */
|
||||
LUAJIT_MODE_FUNC, /* Change mode for a function. */
|
||||
LUAJIT_MODE_ALLFUNC, /* Recurse into subroutine protos. */
|
||||
LUAJIT_MODE_ALLSUBFUNC, /* Change only the subroutines. */
|
||||
|
||||
LUAJIT_MODE_TRACE, /* Flush a compiled trace. */
|
||||
LUAJIT_MODE_TRACE, /* Flush a compiled trace. */
|
||||
|
||||
LUAJIT_MODE_WRAPCFUNC = 0x10, /* Set wrapper mode for C function calls. */
|
||||
LUAJIT_MODE_WRAPCFUNC = 0x10, /* Set wrapper mode for C function calls. */
|
||||
|
||||
LUAJIT_MODE_MAX
|
||||
};
|
||||
|
||||
/* Flags or'ed in to the mode. */
|
||||
#define LUAJIT_MODE_OFF 0x0000 /* Turn feature off. */
|
||||
#define LUAJIT_MODE_ON 0x0100 /* Turn feature on. */
|
||||
#define LUAJIT_MODE_FLUSH 0x0200 /* Flush JIT-compiled code. */
|
||||
#define LUAJIT_MODE_OFF 0x0000 /* Turn feature off. */
|
||||
#define LUAJIT_MODE_ON 0x0100 /* Turn feature on. */
|
||||
#define LUAJIT_MODE_FLUSH 0x0200 /* Flush JIT-compiled code. */
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -8,36 +8,36 @@
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#define LUA_FILEHANDLE "FILE*"
|
||||
#define LUA_FILEHANDLE "FILE*"
|
||||
|
||||
#define LUA_COLIBNAME "coroutine"
|
||||
#define LUA_MATHLIBNAME "math"
|
||||
#define LUA_STRLIBNAME "string"
|
||||
#define LUA_TABLIBNAME "table"
|
||||
#define LUA_IOLIBNAME "io"
|
||||
#define LUA_OSLIBNAME "os"
|
||||
#define LUA_LOADLIBNAME "package"
|
||||
#define LUA_DBLIBNAME "debug"
|
||||
#define LUA_BITLIBNAME "bit"
|
||||
#define LUA_JITLIBNAME "jit"
|
||||
#define LUA_FFILIBNAME "ffi"
|
||||
#define LUA_COLIBNAME "coroutine"
|
||||
#define LUA_MATHLIBNAME "math"
|
||||
#define LUA_STRLIBNAME "string"
|
||||
#define LUA_TABLIBNAME "table"
|
||||
#define LUA_IOLIBNAME "io"
|
||||
#define LUA_OSLIBNAME "os"
|
||||
#define LUA_LOADLIBNAME "package"
|
||||
#define LUA_DBLIBNAME "debug"
|
||||
#define LUA_BITLIBNAME "bit"
|
||||
#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)
|
||||
#define lua_assert(x) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
//////////////////////////////////////////////////
|
||||
// BlFuncs Version 1.0
|
||||
|
||||
|
||||
// Includes
|
||||
|
||||
#include "BlHooks.hpp"
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include "BlFuncs.hpp"
|
||||
#include <Windows.h>
|
||||
#include "BlHooks.hpp"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Scanned structures
|
||||
|
||||
ADDR tsf_mCacheSequence;
|
||||
@@ -18,221 +21,284 @@ ADDR tsf_mCacheAllocator;
|
||||
ADDR tsf_gIdDictionary;
|
||||
ADDR tsf_gEvalState_globalVars;
|
||||
|
||||
BlFunctionDefIntern(tsf_BlStringTable__insert );
|
||||
BlFunctionDefIntern(tsf_BlNamespace__find );
|
||||
BlFunctionDefIntern(tsf_BlStringTable__insert);
|
||||
BlFunctionDefIntern(tsf_BlNamespace__find);
|
||||
BlFunctionDefIntern(tsf_BlNamespace__createLocalEntry);
|
||||
BlFunctionDefIntern(tsf_BlDataChunker__freeBlocks );
|
||||
BlFunctionDefIntern(tsf_BlCon__evaluate );
|
||||
BlFunctionDefIntern(tsf_BlCon__executef );
|
||||
BlFunctionDefIntern(tsf_BlCon__executefSimObj );
|
||||
BlFunctionDefIntern(tsf_BlCon__getVariable );
|
||||
BlFunctionDefIntern(tsf_BlDictionary__addVariable );
|
||||
BlFunctionDefIntern(tsf_BlSim__findObject_name );
|
||||
BlFunctionDefIntern(tsf_BlStringStack__getArgBuffer );
|
||||
BlFunctionDefIntern(tsf_BlSimObject__getDataField );
|
||||
BlFunctionDefIntern(tsf_BlSimObject__setDataField );
|
||||
BlFunctionDefIntern(tsf_BlCon__getReturnBuffer );
|
||||
|
||||
BlFunctionDefIntern(tsf_BlDataChunker__freeBlocks);
|
||||
BlFunctionDefIntern(tsf_BlCon__evaluate);
|
||||
BlFunctionDefIntern(tsf_BlCon__executef);
|
||||
BlFunctionDefIntern(tsf_BlCon__executefSimObj);
|
||||
BlFunctionDefIntern(tsf_BlCon__getVariable);
|
||||
BlFunctionDefIntern(tsf_BlDictionary__addVariable);
|
||||
BlFunctionDefIntern(tsf_BlSim__findObject_name);
|
||||
BlFunctionDefIntern(tsf_BlStringStack__getArgBuffer);
|
||||
BlFunctionDefIntern(tsf_BlSimObject__getDataField);
|
||||
BlFunctionDefIntern(tsf_BlSimObject__setDataField);
|
||||
BlFunctionDefIntern(tsf_BlCon__getReturnBuffer);
|
||||
|
||||
// C->TS Args
|
||||
|
||||
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);
|
||||
snprintf(ret, 32, "%g", value);
|
||||
return ret;
|
||||
}
|
||||
char* tsf_GetStringArg(char* value) {
|
||||
int len = strlen(value)+1;
|
||||
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* ret = tsf_BlStringStack__getArgBuffer(16);
|
||||
snprintf(ret, 16, "%d", value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* tsf_GetFloatArg(float value) {
|
||||
char* ret = tsf_BlStringStack__getArgBuffer(32);
|
||||
snprintf(ret, 32, "%g", value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* tsf_GetStringArg(char* value) {
|
||||
int len = strlen(value) + 1;
|
||||
char* ret = tsf_BlStringStack__getArgBuffer(len);
|
||||
memcpy(ret, value, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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};
|
||||
return tsf_BlCon__evaluate(0, 2, argv);
|
||||
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, ...) {
|
||||
va_list args;
|
||||
char code[4096];
|
||||
va_start(args, fmt);
|
||||
vsnprintf(code, 4096, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return tsf_Eval((const char*)code);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Objects
|
||||
|
||||
ADDR tsf_FindObject(unsigned int id) {
|
||||
ADDR obj = *(ADDR*)(*(ADDR*)(tsf_gIdDictionary) + 4*(id & 0xFFF));
|
||||
if(!obj) return 0;
|
||||
|
||||
while(obj && *(unsigned int *)(obj + 32) != id) {
|
||||
obj = *(ADDR*)(obj + 16);
|
||||
if(!obj) return 0;
|
||||
}
|
||||
|
||||
return obj;
|
||||
ADDR obj = *(ADDR*)(*(ADDR*)(tsf_gIdDictionary) + 4 * (id & 0xFFF));
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
while (obj && *(unsigned int*)(obj + 32) != id) {
|
||||
obj = *(ADDR*)(obj + 16);
|
||||
if (!obj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
if(package) {
|
||||
ste_package = tsf_BlStringTable__insert(package, 0);
|
||||
} else {
|
||||
ste_package = nullptr;
|
||||
}
|
||||
|
||||
if(ns) {
|
||||
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);
|
||||
const char* ste_package;
|
||||
if (package) {
|
||||
ste_package = tsf_BlStringTable__insert(package, 0);
|
||||
} else {
|
||||
ste_package = nullptr;
|
||||
}
|
||||
|
||||
if (ns) {
|
||||
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); }
|
||||
|
||||
// Object Fields
|
||||
|
||||
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 {
|
||||
ste_slotName = nullptr;
|
||||
}
|
||||
|
||||
return tsf_BlSimObject__getDataField(simObject, ste_slotName, array);
|
||||
const char* ste_slotName;
|
||||
if (slotName) {
|
||||
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
||||
} else {
|
||||
ste_slotName = nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
if(slotName) {
|
||||
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
||||
} else {
|
||||
ste_slotName = nullptr;
|
||||
}
|
||||
|
||||
tsf_BlSimObject__setDataField(simObject, ste_slotName, array, value);
|
||||
}
|
||||
const char* ste_slotName;
|
||||
if (slotName) {
|
||||
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
||||
} else {
|
||||
ste_slotName = nullptr;
|
||||
}
|
||||
|
||||
tsf_BlSimObject__setDataField(simObject, ste_slotName, array, value);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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, 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, 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); }
|
||||
|
||||
// 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 ns = tsf_LookupNamespace(cname, pname);
|
||||
ADDR ent = tsf_BlNamespace__createLocalEntry(ns, ste_fname);
|
||||
|
||||
*(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;
|
||||
|
||||
return ent;
|
||||
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);
|
||||
|
||||
*(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_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_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_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_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_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
|
||||
|
||||
bool tsf_InitInternal() {
|
||||
BlScanFunctionText(tsf_BlStringTable__insert , "83 EC 0C 80 3D ? ? ? ? ?" );
|
||||
BlScanFunctionText(tsf_BlNamespace__find , "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 0C 53 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B DA 8B D1" );
|
||||
BlScanFunctionText(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_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_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_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 ? ? ? ?" );
|
||||
|
||||
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;
|
||||
BlScanFunctionText(tsf_BlStringTable__insert, "83 EC 0C 80 3D ? ? ? ? ?");
|
||||
BlScanFunctionText(
|
||||
tsf_BlNamespace__find,
|
||||
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 0C 53 56 57 A1 ? ? ? ? "
|
||||
"33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B DA 8B D1");
|
||||
BlScanFunctionText(
|
||||
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_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_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_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 ? ? ? ?");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool tsf_DeinitInternal() {
|
||||
return true;
|
||||
}
|
||||
bool tsf_DeinitInternal() { return true; }
|
||||
|
||||
@@ -5,49 +5,49 @@
|
||||
#ifndef _H_BLFUNCS
|
||||
#define _H_BLFUNCS
|
||||
|
||||
// Require BlHooks to be included before this header
|
||||
// Ensure BlHooks is available (include it if not already included)
|
||||
#ifndef _H_BLHOOKS
|
||||
#error "BlFuncs.hpp: You must include BlHooks.hpp first"
|
||||
#else
|
||||
#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();
|
||||
|
||||
@@ -56,21 +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
|
||||
|
||||
@@ -94,16 +93,21 @@ BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer, unsigned int
|
||||
|
||||
#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, ...) 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 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 BlFuncsInit() if(!tsf_InitInternal()) { return false; }
|
||||
#define BlFuncsDeinit() if(!tsf_DeinitInternal()) { return false; }
|
||||
#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 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 BlFuncsInit() \
|
||||
if (!tsf_InitInternal()) { \
|
||||
return false; \
|
||||
}
|
||||
#define BlFuncsDeinit() \
|
||||
if (!tsf_DeinitInternal()) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,206 +2,194 @@
|
||||
//////////////////////////////////////////////////
|
||||
// RedoBlHooks Version 3.0
|
||||
|
||||
|
||||
// Includes
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
//#include <map>
|
||||
// #include <map>
|
||||
|
||||
#include "BlHooks.hpp"
|
||||
|
||||
|
||||
// Scanned structures
|
||||
|
||||
BlFunctionDefIntern(tsh_BlPrintf);
|
||||
|
||||
|
||||
// Sig Scanning
|
||||
|
||||
ADDR ImageBase;
|
||||
ADDR ImageSize;
|
||||
|
||||
void tsh_i_InitScanner(){
|
||||
HMODULE module = GetModuleHandle(NULL);
|
||||
if(module) {
|
||||
MODULEINFO info;
|
||||
GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO));
|
||||
ImageBase = (ADDR)info.lpBaseOfDll;
|
||||
ImageSize = info.SizeOfImage;
|
||||
}
|
||||
void tsh_i_InitScanner() {
|
||||
HMODULE module = GetModuleHandle(NULL);
|
||||
if (module) {
|
||||
MODULEINFO info;
|
||||
GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO));
|
||||
ImageBase = (ADDR)info.lpBaseOfDll;
|
||||
ImageSize = info.SizeOfImage;
|
||||
}
|
||||
}
|
||||
|
||||
bool tsh_i_CompareData(BYTE *data, BYTE *pattern, char* mask){
|
||||
for (; *mask; ++data, ++pattern, ++mask){
|
||||
if (*mask=='x' && *data!=*pattern)
|
||||
return false;
|
||||
}
|
||||
return (*mask)==0;
|
||||
bool tsh_i_CompareData(BYTE* data, BYTE* pattern, char* mask) {
|
||||
for (; *mask; ++data, ++pattern, ++mask) {
|
||||
if (*mask == 'x' && *data != *pattern)
|
||||
return false;
|
||||
}
|
||||
return (*mask) == 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert a text-style pattern into code-style
|
||||
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);
|
||||
|
||||
int outidx = 0;
|
||||
int val = 0;
|
||||
bool uk = false;
|
||||
for(unsigned int i=0; i<len; i++){
|
||||
char c = text[i];
|
||||
if(c=='?'){
|
||||
uk = true;
|
||||
}else if(c>='0' && c<='9'){
|
||||
val = (val<<4) + (c-'0');
|
||||
}else if(c>='A' && c<='F'){
|
||||
val = (val<<4) + (c-'A'+10);
|
||||
}else if(c>='a' && c<='f'){
|
||||
val = (val<<4) + (c-'a'+10);
|
||||
}else if(c==' '){
|
||||
patt[outidx] = uk ? 0 : val;
|
||||
mask[outidx] = uk ? '?' : 'x';
|
||||
val = 0;
|
||||
uk = false;
|
||||
outidx++;
|
||||
}
|
||||
}
|
||||
|
||||
patt[outidx] = uk ? 0 : val;
|
||||
mask[outidx] = uk ? '?' : 'x';
|
||||
outidx++;
|
||||
patt[outidx] = 0;
|
||||
mask[outidx] = 0;
|
||||
|
||||
*opatt = patt;
|
||||
*omask = mask;
|
||||
}
|
||||
unsigned int len = strlen(text);
|
||||
char* patt = (char*)malloc(len);
|
||||
char* mask = (char*)malloc(len);
|
||||
|
||||
int outidx = 0;
|
||||
int val = 0;
|
||||
bool uk = false;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
char c = text[i];
|
||||
if (c == '?') {
|
||||
uk = true;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
val = (val << 4) + (c - '0');
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
val = (val << 4) + (c - 'A' + 10);
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
val = (val << 4) + (c - 'a' + 10);
|
||||
} else if (c == ' ') {
|
||||
patt[outidx] = uk ? 0 : val;
|
||||
mask[outidx] = uk ? '?' : 'x';
|
||||
val = 0;
|
||||
uk = false;
|
||||
outidx++;
|
||||
}
|
||||
}
|
||||
|
||||
patt[outidx] = uk ? 0 : val;
|
||||
mask[outidx] = uk ? '?' : 'x';
|
||||
outidx++;
|
||||
patt[outidx] = 0;
|
||||
mask[outidx] = 0;
|
||||
|
||||
*opatt = patt;
|
||||
*omask = mask;
|
||||
}
|
||||
|
||||
// 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);
|
||||
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;
|
||||
tsh_i_PatternTextToCode(text, &patt, &mask);
|
||||
|
||||
ADDR res = tsh_ScanCode(patt, mask);
|
||||
|
||||
free(patt);
|
||||
free(mask);
|
||||
|
||||
return res;
|
||||
}
|
||||
char* patt;
|
||||
char* mask;
|
||||
tsh_i_PatternTextToCode(text, &patt, &mask);
|
||||
|
||||
ADDR res = tsh_ScanCode(patt, mask);
|
||||
|
||||
free(patt);
|
||||
free(mask);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Call Patching and Hooking
|
||||
|
||||
// Remove protection from address
|
||||
//std::map<ADDR, std::pair<ADDR, ADDR>> tsh_DeprotectedAddresses;
|
||||
// std::map<ADDR, std::pair<ADDR, ADDR>> tsh_DeprotectedAddresses;
|
||||
|
||||
void tsh_DeprotectAddress(ADDR length, ADDR location) {
|
||||
DWORD oldProtection;
|
||||
VirtualProtect((void*)location, length, PAGE_EXECUTE_READWRITE, &oldProtection);
|
||||
//tsh_DeprotectedAddresses[location] = {length, oldProtection};
|
||||
DWORD 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) {
|
||||
tsh_DeprotectAddress(length, location);
|
||||
memcpy((void*)location, (void*)repl, (size_t)length);
|
||||
tsh_DeprotectAddress(length, location);
|
||||
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);
|
||||
}
|
||||
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)));
|
||||
}
|
||||
for (unsigned int i = 0; i < len; 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
|
||||
|
||||
*(BYTE*)victim = 0xE9; //jmp rel32
|
||||
*(ADDR*)(victim+1) = (detour - (victim+5)); // jump offset
|
||||
*(BYTE*)(victim+5) = 0xC3; //retn
|
||||
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
|
||||
}
|
||||
|
||||
void tsh_UnhookFunction(ADDR victim, BYTE* origbytes){
|
||||
tsh_i_PatchCopy(victim, (ADDR)origbytes, 6); //restore old data
|
||||
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 numpatched = 0;
|
||||
for(ADDR i=ImageBase; i<ImageBase+ImageSize-len; i++){
|
||||
if(tsh_i_CompareData((BYTE*)i, (BYTE*)patt, mask)){
|
||||
if(debugprint) BlPrintf("RedoBlHooks: Patching call at %08x", i);
|
||||
|
||||
numpatched++;
|
||||
tsh_DeprotectAddress(i, len);
|
||||
for(ADDR c=0; c<len; c++){
|
||||
tsh_PatchByte(i+c, replace[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return numpatched;
|
||||
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 (debugprint)
|
||||
BlPrintf("RedoBlHooks: Patching call at %08x", i);
|
||||
|
||||
numpatched++;
|
||||
tsh_DeprotectAddress(i, len);
|
||||
for (ADDR c = 0; c < len; c++) {
|
||||
tsh_PatchByte(i + c, replace[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return numpatched;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
free(patt);
|
||||
free(mask);
|
||||
|
||||
return res;
|
||||
}
|
||||
char* patt;
|
||||
char* mask;
|
||||
tsh_i_PatternTextToCode(text, &patt, &mask);
|
||||
|
||||
int res = tsh_PatchAllMatchesCode(len, patt, mask, replace, debugprint);
|
||||
|
||||
free(patt);
|
||||
free(mask);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Initialization
|
||||
|
||||
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");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tsh_DeinitInternal() {
|
||||
return true;
|
||||
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");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tsh_DeinitInternal() { return true; }
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
#ifndef _H_BLHOOKS
|
||||
#define _H_BLHOOKS
|
||||
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned int ADDR;
|
||||
|
||||
typedef unsigned int ADDR;
|
||||
|
||||
// Prototypes
|
||||
|
||||
@@ -20,103 +18,114 @@ 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);
|
||||
int tsh_PatchAllMatches(unsigned int, char*, char*, char*, bool);
|
||||
void tsh_PatchByte(ADDR, BYTE);
|
||||
void tsh_PatchBytes(unsigned int, ADDR, BYTE*);
|
||||
void tsh_PatchInt(ADDR, int);
|
||||
|
||||
|
||||
// Debug print settings
|
||||
|
||||
#ifndef TSH_NO_DEBUG_PRINT
|
||||
#define tsh_DEBUGPRINT false
|
||||
#define tsh_DEBUGPRINT false
|
||||
#else
|
||||
#define tsh_DEBUGPRINT true
|
||||
#define tsh_DEBUGPRINT true
|
||||
#endif
|
||||
|
||||
|
||||
// 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__); \
|
||||
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__); \
|
||||
extern tsh_##name##FnT name;
|
||||
// Use in code for shared function defs when a BlFunctionDefExtern exists in header
|
||||
#define BlFunctionDefIntern(name) \
|
||||
tsh_##name##FnT name;
|
||||
#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__); \
|
||||
extern tsh_##name##FnT name;
|
||||
// Use in code for shared function defs when a BlFunctionDefExtern exists in
|
||||
// header
|
||||
#define BlFunctionDefIntern(name) tsh_##name##FnT name;
|
||||
|
||||
// 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 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 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); \
|
||||
}
|
||||
// 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 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 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); \
|
||||
func##HookOn();
|
||||
#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);
|
||||
#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*, ...);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
347
readme.md
347
readme.md
@@ -1,219 +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 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)
|
||||
|
||||
`'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
|
||||
|
||||
`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
|
||||
`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'`
|
||||
|
||||
`'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...) ... 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
|
||||
|
||||
`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) ... 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(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.
|
||||
|
||||
`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
|
||||
|
||||
`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
|
||||
`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)`
|
||||
|
||||
`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.
|
||||
|
||||
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
|
||||
- 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
|
||||
|
||||
- `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`.
|
||||
|
||||
- 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.
|
||||
|
||||
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.
|
||||
|
||||
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`
|
||||
|
||||
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/
|
||||
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/
|
||||
|
||||
165
src/bllua4.cpp
165
src/bllua4.cpp
@@ -2,12 +2,15 @@
|
||||
|
||||
// Includes
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
|
||||
#include "lua.hpp"
|
||||
#include "BlHooks.cpp"
|
||||
#include "BlFuncs.cpp"
|
||||
#include "BlHooks.cpp"
|
||||
#include "lua.hpp"
|
||||
|
||||
#include "luainterp.cpp"
|
||||
#include "lualibts.cpp"
|
||||
@@ -19,92 +22,96 @@ 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"); \
|
||||
extern char varname[];
|
||||
#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" );
|
||||
INCLUDE_BIN(bll_fileLuaLibblTypes , "util/libbl-types.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");
|
||||
INCLUDE_BIN(bll_fileLuaLibblTypes, "util/libbl-types.lua");
|
||||
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
|
||||
INCLUDE_BIN(bll_fileLoadaddons , "util/loadaddons.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() {
|
||||
BlHooksInit();
|
||||
BlPrintf("BlockLua: Loading");
|
||||
|
||||
BlFuncsInit();
|
||||
|
||||
// Initialize Lua environment
|
||||
gL = lua_open();
|
||||
luaL_openlibs(gL);
|
||||
|
||||
// Expose TS API to Lua
|
||||
llibbl_init(gL);
|
||||
|
||||
// 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
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
BlEval("$_bllua_active = 1;");
|
||||
|
||||
BlPrintf(" BlockLua: Done Loading");
|
||||
return true;
|
||||
BlHooksInit();
|
||||
BlPrintf("BlockLua: Loading");
|
||||
|
||||
BlFuncsInit();
|
||||
|
||||
// Initialize Lua environment
|
||||
gL = lua_open();
|
||||
luaL_openlibs(gL);
|
||||
|
||||
// Expose TS API to Lua
|
||||
llibbl_init(gL);
|
||||
|
||||
// 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
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
BlEval("$_bllua_active = 1;");
|
||||
|
||||
BlPrintf(" BlockLua: Done Loading");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool deinit() {
|
||||
BlPrintf("BlockLua: Unloading");
|
||||
|
||||
BlEval("$_bllua_active=0;deactivatePackage(_bllua_main);");
|
||||
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
||||
|
||||
lua_close(gL);
|
||||
|
||||
BlHooksDeinit();
|
||||
BlFuncsDeinit();
|
||||
|
||||
BlPrintf(" BlockLua: Done Unloading");
|
||||
return true;
|
||||
BlPrintf("BlockLua: Unloading");
|
||||
|
||||
BlEval("$_bllua_active=0;deactivatePackage(_bllua_main);");
|
||||
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
||||
|
||||
lua_close(gL);
|
||||
|
||||
BlHooksDeinit();
|
||||
BlFuncsDeinit();
|
||||
|
||||
BlPrintf(" BlockLua: Done Unloading");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __stdcall DllMain(HINSTANCE hinstance, DWORD reason, void* reserved) {
|
||||
switch(reason) {
|
||||
case DLL_PROCESS_ATTACH: return init();
|
||||
case DLL_PROCESS_DETACH: return deinit();
|
||||
default : return true;
|
||||
}
|
||||
switch (reason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
return init();
|
||||
case DLL_PROCESS_DETACH:
|
||||
return deinit();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
-- Sanitize the Lua environment to:
|
||||
-- Prevent scripts from accessing files outside the game directory
|
||||
-- Prevent usage of libraries other than
|
||||
-- Prevent usage of libraries other than
|
||||
|
||||
|
||||
-- Utility: Convert a list of strings into a map of string->true
|
||||
local function tmap(t) local u = {}; for _, n in ipairs(t) do u[n] = true end; return u; end
|
||||
local function tmap(t)
|
||||
local u = {}; for _, n in ipairs(t) do u[n] = true end; return u;
|
||||
end
|
||||
|
||||
-- Save banned global variables for wrapping with safe functions
|
||||
local old_io = io
|
||||
@@ -16,96 +18,100 @@ local old_allowffi = _bllua_allowffi
|
||||
|
||||
-- Remove all global variables except a whitelist
|
||||
local ok_names = tmap {
|
||||
'_G', '_bllua_ts', '_bllua_on_unload', '_bllua_on_error',
|
||||
'string', 'table', 'math', 'coroutine', 'bit',
|
||||
'pairs', 'ipairs', 'next', 'unpack', 'select',
|
||||
'error', 'assert', 'pcall', 'xpcall',
|
||||
'type', 'tostring', 'tonumber',
|
||||
'loadstring',
|
||||
'getmetatable', 'setmetatable',
|
||||
'rawget', 'rawset', 'rawequal', 'rawlen',
|
||||
'module', '_VERSION',
|
||||
'_G', '_bllua_ts', '_bllua_on_unload', '_bllua_on_error',
|
||||
'string', 'table', 'math', 'coroutine', 'bit',
|
||||
'pairs', 'ipairs', 'next', 'unpack', 'select',
|
||||
'error', 'assert', 'pcall', 'xpcall',
|
||||
'type', 'tostring', 'tonumber',
|
||||
'loadstring',
|
||||
'getmetatable', 'setmetatable',
|
||||
'rawget', 'rawset', 'rawequal', 'rawlen',
|
||||
'module', '_VERSION',
|
||||
}
|
||||
local not_ok_names = {}
|
||||
for n, _ in pairs(_G) do
|
||||
if not ok_names[n] then
|
||||
table.insert(not_ok_names, n)
|
||||
end
|
||||
if not ok_names[n] then
|
||||
table.insert(not_ok_names, n)
|
||||
end
|
||||
end
|
||||
for _, n in ipairs(not_ok_names) do
|
||||
_G[n] = nil
|
||||
_G[n] = nil
|
||||
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'
|
||||
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
||||
}
|
||||
-- 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,
|
||||
-- so this is just a precaution.
|
||||
local disallowed_exts = tmap {
|
||||
-- windows
|
||||
'bat','bin','cab','cmd','com','cpl','ex_','exe','gadget','inf','ins','inx','isu',
|
||||
'job','jse','lnk','msc','msi','msp','mst','paf','pif','ps1','reg','rgs','scr',
|
||||
'sct','shb','shs','u3p','vb','vbe','vbs','vbscript','ws','wsf','wsh',
|
||||
-- linux
|
||||
'csh','ksh','out','run','sh',
|
||||
-- mac/other
|
||||
'action','apk','app','command','ipa','osx','prg','workflow',
|
||||
-- windows
|
||||
'bat', 'bin', 'cab', 'cmd', 'com', 'cpl', 'ex_', 'exe', 'gadget', 'inf', 'ins', 'inx', 'isu',
|
||||
'job', 'jse', 'lnk', 'msc', 'msi', 'msp', 'mst', 'paf', 'pif', 'ps1', 'reg', 'rgs', 'scr',
|
||||
'sct', 'shb', 'shs', 'u3p', 'vb', 'vbe', 'vbs', 'vbscript', 'ws', 'wsf', 'wsh',
|
||||
-- linux
|
||||
'csh', 'ksh', 'out', 'run', 'sh',
|
||||
-- mac/other
|
||||
'action', 'apk', 'app', 'command', 'ipa', 'osx', 'prg', 'workflow',
|
||||
}
|
||||
-- Arguments: file name (relative to game directory), boolean true if only reading
|
||||
-- Return: clean file path if allowed (or nil if disallowed),
|
||||
-- error string (or nil if allowed)
|
||||
local function safe_path(fn, readonly)
|
||||
fn = fn:gsub('\\', '/')
|
||||
fn = fn:gsub('^ +', '')
|
||||
fn = fn:gsub(' +$', '')
|
||||
-- whitelist characters
|
||||
local ic = fn:find('[^a-zA-Z0-9_%-/ %.]')
|
||||
if ic then
|
||||
return nil, 'Filename \''..fn..'\' contains invalid character \''..
|
||||
fn:sub(ic, ic)..'\' at position '..ic
|
||||
end
|
||||
-- disallow up-dirs, absolute paths, and relative paths
|
||||
-- './' and '../' are possible in scripts, because they're processed into
|
||||
-- absolute paths in util.lua before reaching here
|
||||
if fn:find('^%.') or fn:find('%.%.') or fn:find(':') or fn:find('^/') then
|
||||
return nil, 'Filename \''..fn..'\' contains invalid sequence'
|
||||
end
|
||||
-- allow only whitelisted dirs
|
||||
local dir = fn:match('^([^/]+)/')
|
||||
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
|
||||
local ext = fn:match('%.([^/%.]+)$')
|
||||
if ext and disallowed_exts[ext:lower()] then
|
||||
return nil, 'Filename \''..fn..'\' has disallowed extension \''..
|
||||
(ext or '')..'\''
|
||||
end
|
||||
return fn, nil
|
||||
if type(fn) ~= 'string' then
|
||||
return nil, 'Filename must be a string'
|
||||
end
|
||||
fn = fn:gsub('\\', '/')
|
||||
fn = fn:gsub('^ +', '')
|
||||
fn = fn:gsub(' +$', '')
|
||||
-- whitelist characters
|
||||
local ic = fn:find('[^a-zA-Z0-9_%-/ %.]')
|
||||
if ic then
|
||||
return nil, 'Filename \'' .. fn .. '\' contains invalid character \'' ..
|
||||
fn:sub(ic, ic) .. '\' at position ' .. ic
|
||||
end
|
||||
-- disallow up-dirs, absolute paths, and relative paths
|
||||
-- './' and '../' are possible in scripts, because they're processed into
|
||||
-- absolute paths in util.lua before reaching here
|
||||
if fn:find('^%.') or fn:find('%.%.') or fn:find(':') or fn:find('^/') then
|
||||
return nil, 'Filename \'' .. fn .. '\' contains invalid sequence'
|
||||
end
|
||||
-- allow only whitelisted dirs
|
||||
local dir = fn:match('^([^/]+)/')
|
||||
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
|
||||
local ext = fn:match('%.([^/%.]+)$')
|
||||
if ext and disallowed_exts[ext:lower()] then
|
||||
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
|
||||
(ext or '') .. '\''
|
||||
end
|
||||
return fn, nil
|
||||
end
|
||||
|
||||
-- Wrap io.open with path sanitization
|
||||
function _bllua_io_open(fn, md)
|
||||
md = md or 'r'
|
||||
local readonly = md=='r' or md=='rb'
|
||||
local fns, err = safe_path(fn, readonly)
|
||||
if fns then
|
||||
return old_io.open(fns, md)
|
||||
else
|
||||
return nil, err
|
||||
end
|
||||
md = md or 'r'
|
||||
local readonly = md == 'r' or md == 'rb'
|
||||
local fns, err = safe_path(fn, readonly)
|
||||
if fns then
|
||||
return old_io.open(fns, md)
|
||||
else
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
-- Allow io.type (works on file handles returned by io.open)
|
||||
function _bllua_io_type(f)
|
||||
return old_io.type(f)
|
||||
return old_io.type(f)
|
||||
end
|
||||
|
||||
-- Wrap require with a blacklist for unsafe built-in modules
|
||||
@@ -113,30 +119,31 @@ end
|
||||
-- Note that util.lua wraps this and provides 'require',
|
||||
-- only falling back here if the package is not found in user files
|
||||
local disallowed_packages = tmap {
|
||||
'ffi', 'debug', 'package', 'io', 'os',
|
||||
'_bllua_ts',
|
||||
'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
|
||||
error('require: package name contains invalid character', 3)
|
||||
elseif disallowed_packages[name] then
|
||||
error('require: attempt to require disallowed module \''..name..'\'', 3)
|
||||
else
|
||||
-- todo: reimplement require to not use package.* stuff?
|
||||
return old_require(name)
|
||||
end
|
||||
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
|
||||
name:find('^%.') or name:find('%.$') then
|
||||
error('require: package name contains invalid character', 3)
|
||||
elseif disallowed_packages[name] then
|
||||
error('require: attempt to require disallowed module \'' .. name .. '\'', 3)
|
||||
else
|
||||
-- todo: reimplement require to not use package.* stuff?
|
||||
return old_require(name)
|
||||
end
|
||||
end
|
||||
|
||||
package = {
|
||||
seeall = old_package.seeall,
|
||||
seeall = old_package.seeall,
|
||||
}
|
||||
|
||||
-- Provide limited debug
|
||||
debug = {
|
||||
traceback = old_debug.traceback,
|
||||
getinfo = old_debug.getinfo,
|
||||
getfilename = old_debug.getfilename, -- defined in lua.env.lua
|
||||
traceback = old_debug.traceback,
|
||||
getinfo = old_debug.getinfo,
|
||||
getfilename = old_debug.getfilename, -- defined in lua.env.lua
|
||||
}
|
||||
|
||||
print = _bllua_ts.echo
|
||||
|
||||
@@ -9,32 +9,34 @@ _bllua_on_unload = {}
|
||||
|
||||
-- Utility for getting the current filename
|
||||
function debug.getfilename(level)
|
||||
if type(level) == 'number' then level = level+1 end
|
||||
local info = debug.getinfo(level)
|
||||
if not info then return nil end
|
||||
local filename = info.source:match('^%-%-%[%[([^%]]+)%]%]')
|
||||
return filename
|
||||
if type(level) == 'number' then level = level + 1 end
|
||||
local info = debug.getinfo(level)
|
||||
if not info then return nil end
|
||||
local filename = info.source:match('^%-%-%[%[([^%]]+)%]%]')
|
||||
return filename
|
||||
end
|
||||
|
||||
-- Called when pcall fails on a ts->lua call, used to print detailed error info
|
||||
function _bllua_on_error(err)
|
||||
err = err:match(': (.+)$') or err
|
||||
local tracelines = {err}
|
||||
local level = 2
|
||||
while true do
|
||||
local info = debug.getinfo(level)
|
||||
if not info then break end
|
||||
local filename = debug.getfilename(level) or info.short_src
|
||||
local funcname = info.name
|
||||
if funcname=='dofile' then break end
|
||||
table.insert(tracelines, string.format('%s:%s in function \'%s\'',
|
||||
filename,
|
||||
info.currentline==-1 and '' or info.currentline..':',
|
||||
funcname
|
||||
))
|
||||
level = level+1
|
||||
end
|
||||
return table.concat(tracelines, '\n')
|
||||
-- Convert error to string if it's not already
|
||||
err = tostring(err)
|
||||
err = err:match(': (.+)$') or err
|
||||
local tracelines = { err }
|
||||
local level = 2
|
||||
while true do
|
||||
local info = debug.getinfo(level)
|
||||
if not info then break end
|
||||
local filename = debug.getfilename(level) or info.short_src
|
||||
local funcname = info.name or '<unknown>'
|
||||
if funcname == 'dofile' then break end
|
||||
table.insert(tracelines, string.format('%s:%s in function \'%s\'',
|
||||
filename,
|
||||
info.currentline == -1 and '' or info.currentline .. ':',
|
||||
funcname
|
||||
))
|
||||
level = level + 1
|
||||
end
|
||||
return table.concat(tracelines, '\n')
|
||||
end
|
||||
|
||||
-- overridden in lua-env-safe.lua (executed if not BLLUA_UNSAFE)
|
||||
|
||||
@@ -1,68 +1,81 @@
|
||||
|
||||
// Handle errors with a Lua function, defined in lua-env.lua
|
||||
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.");
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// move function to before arg
|
||||
int hpos = lua_gettop(L) - 1;
|
||||
lua_insert(L, hpos);
|
||||
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
return 1;
|
||||
#include "luainterp.hpp"
|
||||
#include "BlHooks.hpp"
|
||||
#include "lauxlib.h"
|
||||
#include "lua.h"
|
||||
#include <cstring>
|
||||
|
||||
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.");
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// move function to before arg
|
||||
int hpos = lua_gettop(L) - 1;
|
||||
lua_insert(L, hpos);
|
||||
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
lua_pushcfunction(L, bll_error_handler);
|
||||
// move it before function and arguments
|
||||
lua_insert(L, hpos);
|
||||
// call lua_pcall function with custom handler
|
||||
int ret = lua_pcall(L, nargs, nret, hpos);
|
||||
// remove custom error message handler from stack
|
||||
lua_remove(L, hpos);
|
||||
return ret;
|
||||
// calculate stack position for message handler
|
||||
int hpos = lua_gettop(L) - nargs;
|
||||
// push custom error message handler
|
||||
lua_pushcfunction(L, bll_error_handler);
|
||||
// move it before function and arguments
|
||||
lua_insert(L, hpos);
|
||||
// call lua_pcall function with custom handler
|
||||
int ret = lua_pcall(L, nargs, nret, hpos);
|
||||
// remove custom error message handler from stack
|
||||
lua_remove(L, hpos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Display the last Lua error in the BL console
|
||||
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);
|
||||
lua_pop(L, 1);
|
||||
// error_handler(L);
|
||||
BlPrintf("\x03Lua error: %s", lua_tostring(L, -1));
|
||||
BlPrintf("\x03 (%s: %s)", operation, item);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
// Eval a string of Lua code
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
if (luaL_loadbuffer(L, str, strlen(str), "input") || bll_pcall(L, 0, 1)) {
|
||||
bll_printError(L, "eval", str);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert a Lua stack entry into a string for providing to TS
|
||||
// Use static buffer to avoid excessive malloc
|
||||
#define BLL_ARG_COUNT 20
|
||||
#define BLL_ARG_MAX 8192
|
||||
char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
|
||||
|
||||
bool bll_toarg(lua_State* L, char* buf, int i, bool err) {
|
||||
if(lua_isstring(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");
|
||||
return true;
|
||||
} else {
|
||||
strcpy(buf, str);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(err) luaL_error(L, "argument to TS must be a string");
|
||||
return true;
|
||||
}
|
||||
if (lua_isstring(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");
|
||||
return true;
|
||||
} else {
|
||||
#ifdef _MSC_VER
|
||||
strncpy_s(buf, BLL_ARG_MAX, str, _TRUNCATE);
|
||||
#else
|
||||
strncpy(buf, str, BLL_ARG_MAX - 1);
|
||||
buf[BLL_ARG_MAX - 1] = '\0';
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (err)
|
||||
luaL_error(L, "argument to TS must be a string");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
17
src/luainterp.hpp
Normal file
17
src/luainterp.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Shared declarations for Lua <-> TS argument handling
|
||||
#ifndef _H_LUAINTERP_SHARED
|
||||
#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);
|
||||
|
||||
extern lua_State* gL;
|
||||
|
||||
#endif
|
||||
384
src/lualibts.cpp
384
src/lualibts.cpp
@@ -1,159 +1,295 @@
|
||||
//run ../compile
|
||||
// run ../compile
|
||||
|
||||
// TS -> Lua API
|
||||
|
||||
// Call a TS function from Lua, push the result to Lua stack
|
||||
#include "BlFuncs.hpp"
|
||||
#include "BlHooks.hpp"
|
||||
#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) {
|
||||
ADDR obj = (ADDR)NULL;
|
||||
if(oname) {
|
||||
obj = BlObject(oname);
|
||||
if(!obj) { return luaL_error(L, "Lua->TS call: Object not found"); }
|
||||
}
|
||||
|
||||
if(argc > BLL_ARG_COUNT) { return luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)"); }
|
||||
|
||||
char* argv[BLL_ARG_COUNT];
|
||||
for(int i=0; i<argc; i++) {
|
||||
char* argbuf = bll_arg_buffer[i];
|
||||
argv[i] = argbuf;
|
||||
bll_toarg(L, argbuf, i+ofs+1, true);
|
||||
}
|
||||
|
||||
// /:^| /
|
||||
const char* res;
|
||||
if(obj) {
|
||||
switch(argc) {
|
||||
case 0: res = BlCallObj(obj, fname); break; // no idea why this happens sometimes, it shouldnt be possible
|
||||
case 1: res = BlCallObj(obj, fname); break;
|
||||
case 2: res = BlCallObj(obj, fname, argv[0]); break;
|
||||
case 3: res = BlCallObj(obj, fname, argv[0], argv[1]); break;
|
||||
case 4: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2]); break;
|
||||
case 5: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3]); break;
|
||||
case 6: 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]); break;
|
||||
case 8: 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); break;
|
||||
default: res = ""; luaL_error(L, "Lua->TS object call: Too many arguments (Max is 19)");
|
||||
}
|
||||
} else {
|
||||
switch(argc) {
|
||||
case 0: res = BlCall(fname); break;
|
||||
case 1: res = BlCall(fname, argv[0]); break;
|
||||
case 2: res = BlCall(fname, argv[0], argv[1]); break;
|
||||
case 3: res = BlCall(fname, argv[0], argv[1], argv[2]); break;
|
||||
case 4: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3]); break;
|
||||
case 5: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4]); break;
|
||||
case 6: 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]); break;
|
||||
case 8: 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); 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]); break;
|
||||
default: res = ""; luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushstring(L, res);
|
||||
|
||||
return 1;
|
||||
ADDR obj = (ADDR)NULL;
|
||||
if (oname) {
|
||||
obj = BlObject(oname);
|
||||
if (!obj) {
|
||||
return luaL_error(L, "Lua->TS call: Object not found");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > BLL_ARG_COUNT) {
|
||||
return luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
||||
}
|
||||
|
||||
char* argv[BLL_ARG_COUNT];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char* argbuf = bll_arg_buffer[i];
|
||||
argv[i] = argbuf;
|
||||
bll_toarg(L, argbuf, i + ofs + 1, true);
|
||||
}
|
||||
|
||||
// /:^| /
|
||||
const char* res;
|
||||
if (obj) {
|
||||
switch (argc) {
|
||||
case 0:
|
||||
res = BlCallObj(obj, fname);
|
||||
break; // no idea why this happens sometimes, it shouldnt be possible
|
||||
case 1:
|
||||
res = BlCallObj(obj, fname);
|
||||
break;
|
||||
case 2:
|
||||
res = BlCallObj(obj, fname, argv[0]);
|
||||
break;
|
||||
case 3:
|
||||
res = BlCallObj(obj, fname, argv[0], argv[1]);
|
||||
break;
|
||||
case 4:
|
||||
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2]);
|
||||
break;
|
||||
case 5:
|
||||
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3]);
|
||||
break;
|
||||
case 6:
|
||||
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]);
|
||||
break;
|
||||
case 8:
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
break;
|
||||
default:
|
||||
res = "";
|
||||
luaL_error(L, "Lua->TS object call: Too many arguments (Max is 19)");
|
||||
}
|
||||
} else {
|
||||
switch (argc) {
|
||||
case 0:
|
||||
res = BlCall(fname);
|
||||
break;
|
||||
case 1:
|
||||
res = BlCall(fname, argv[0]);
|
||||
break;
|
||||
case 2:
|
||||
res = BlCall(fname, argv[0], argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
res = BlCall(fname, argv[0], argv[1], argv[2]);
|
||||
break;
|
||||
case 4:
|
||||
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3]);
|
||||
break;
|
||||
case 5:
|
||||
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
break;
|
||||
case 6:
|
||||
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]);
|
||||
break;
|
||||
case 8:
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
break;
|
||||
default:
|
||||
res = "";
|
||||
luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushstring(L, res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua lib function: ts.call
|
||||
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);
|
||||
|
||||
return bll_TsCall(L, NULL, fname, argc, 1);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return bll_TsCall(L, oname, fname, argc, 2);
|
||||
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);
|
||||
|
||||
const char* var = BlGetVar(vname);
|
||||
lua_pushstring(L, var);
|
||||
return 1;
|
||||
const char* vname = luaL_checkstring(L, 1);
|
||||
|
||||
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);
|
||||
ADDR obj = BlObject(oname);
|
||||
if(!obj) { return luaL_error(L, "_bllua_ts.getfield: Object not found"); }
|
||||
|
||||
const char* val = BlGetField(obj, vname, NULL);
|
||||
lua_pushstring(L, val);
|
||||
return 1;
|
||||
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);
|
||||
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);
|
||||
ADDR obj = BlObject(oname);
|
||||
if(!obj) { return luaL_error(L, "_bllua_ts.setfield: Object not found"); }
|
||||
|
||||
BlSetField(obj, vname, NULL, val);
|
||||
return 0;
|
||||
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");
|
||||
}
|
||||
|
||||
BlSetField(obj, vname, NULL, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua lib function: ts.eval
|
||||
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;
|
||||
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);
|
||||
BlPrintf("%s", str);
|
||||
return 0;
|
||||
const char* str = luaL_checkstring(L, 1);
|
||||
BlPrintf("%s", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg bll_lua_reg[] = {
|
||||
{"call" , bll_lua_tscall },
|
||||
{"callobj" , bll_lua_tscallobj },
|
||||
{"getvar" , bll_lua_tsgetvar },
|
||||
{"getfield", bll_lua_tsgetfield},
|
||||
{"setfield", bll_lua_tssetfield},
|
||||
{"eval" , bll_lua_tseval },
|
||||
{"echo" , bll_lua_tsecho },
|
||||
{NULL, NULL},
|
||||
{"call", bll_lua_tscall}, {"callobj", bll_lua_tscallobj},
|
||||
{"getvar", bll_lua_tsgetvar}, {"getfield", bll_lua_tsgetfield},
|
||||
{"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); }
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
|
||||
// Call a Lua function from TS, return true if success - result will be on Lua stack
|
||||
// Call a Lua function from TS, return true if success - result will be on Lua
|
||||
// stack
|
||||
#include "BlFuncs.hpp"
|
||||
#include "BlHooks.hpp"
|
||||
#include "luainterp.hpp"
|
||||
|
||||
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]);
|
||||
}
|
||||
if(bll_pcall(gL, argc, 1)) {
|
||||
bll_printError(gL, "call", fname);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
lua_getglobal(gL, fname);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
lua_pushstring(gL, argv[i]);
|
||||
}
|
||||
if (bll_pcall(gL, argc, 1)) {
|
||||
bll_printError(gL, "call", fname);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TS lib function: luacall
|
||||
const char* bll_ts_luacall(ADDR obj, int argc, const char* argv[]) {
|
||||
if(argc<2) return "";
|
||||
|
||||
if(!bll_LuaCall(argv[1], argc-2, &argv[2])) { return ""; }
|
||||
|
||||
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;
|
||||
if (argc < 2)
|
||||
return "";
|
||||
|
||||
if (!bll_LuaCall(argv[1], argc - 2, &argv[2])) {
|
||||
return "";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -4,129 +4,129 @@
|
||||
|
||||
-- Class hierarchy, adapted from https://notabug.org/Queuenard/blockland-DLL-tools/src/master/class_hierarchy
|
||||
bl.class('SimObject')
|
||||
bl.class('ScriptObject', 'SimObject')
|
||||
bl.class('SimSet', 'SimObject')
|
||||
bl.class('SimGroup', 'SimSet')
|
||||
bl.class('GuiControl', 'SimGroup')
|
||||
bl.class('GuiTextCtrl' , 'GuiControl')
|
||||
bl.class('GuiSwatchCtrl' , 'GuiControl')
|
||||
bl.class('GuiButtonBaseCtrl' , 'GuiControl')
|
||||
bl.class('GuiArrayCtrl' , 'GuiControl')
|
||||
bl.class('GuiScrollCtrl' , 'GuiControl')
|
||||
bl.class('GuiMouseEventCtrl' , 'GuiControl')
|
||||
bl.class('GuiProgressCtrl' , 'GuiControl')
|
||||
bl.class('GuiSliderCtrl' , 'GuiControl')
|
||||
bl.class('GuiConsoleTextCtrl' , 'GuiControl')
|
||||
bl.class('GuiTSCtrl' , 'GuiControl')
|
||||
bl.class('GuiObjectView', 'GuiTSCtrl')
|
||||
bl.class('GameTSCtrl' , 'GuiTSCtrl')
|
||||
bl.class('EditTSCtrl' , 'GuiTSCtrl')
|
||||
bl.class('GuiPlayerView', 'GuiTSCtrl')
|
||||
bl.class('GuiShapeNameHud' , 'GuiControl')
|
||||
bl.class('GuiHealthBarHud' , 'GuiControl')
|
||||
bl.class('GuiGraphCtrl' , 'GuiControl')
|
||||
bl.class('GuiInspector' , 'GuiControl')
|
||||
bl.class('GuiChunkedBitmapCtrl', 'GuiControl')
|
||||
bl.class('GuiInputCtrl' , 'GuiControl')
|
||||
bl.class('GuiNoMouseCtrl' , 'GuiControl')
|
||||
bl.class('GuiBitmapBorderCtrl' , 'GuiControl')
|
||||
bl.class('GuiBackgroundCtrl' , 'GuiControl')
|
||||
bl.class('GuiEditorRuler' , 'GuiControl')
|
||||
bl.class('GuiClockHud' , 'GuiControl')
|
||||
bl.class('GuiEditCtrl' , 'GuiControl')
|
||||
bl.class('GuiFilterCtrl' , 'GuiControl')
|
||||
bl.class('GuiFrameSetCtrl' , 'GuiControl')
|
||||
bl.class('GuiMenuBar' , 'GuiControl')
|
||||
bl.class('GuiMessageVectorCtrl', 'GuiControl')
|
||||
bl.class('GuiBitmapCtrl' , 'GuiControl')
|
||||
bl.class('GuiCrossHairHud', 'GuiBitmapCtrl')
|
||||
bl.class('ScriptGroup', 'SimGroup')
|
||||
bl.class('NetConnection', 'SimGroup')
|
||||
bl.class('GameConnection', 'NetConnection')
|
||||
bl.class('Path', 'SimGroup')
|
||||
bl.class('TCPObject', 'SimObject')
|
||||
bl.class('SOCKObject', 'TCPObject')
|
||||
bl.class('HTTPObject', 'TCPObject')
|
||||
bl.class('SimDataBlock', 'SimObject')
|
||||
bl.class('AudioEnvironment' , 'SimDataBlock')
|
||||
bl.class('AudioSampleEnvironment', 'SimDataBlock')
|
||||
bl.class('AudioDescription' , 'SimDataBlock')
|
||||
bl.class('GameBaseData' , 'SimDataBlock')
|
||||
bl.class('ShapeBaseData' , 'GameBaseData')
|
||||
bl.class('CameraData' , 'ShapeBaseData')
|
||||
bl.class('ItemData' , 'ShapeBaseData')
|
||||
bl.class('MissionMarkerData', 'ShapeBaseData')
|
||||
bl.class('PathCameraData' , 'ShapeBaseData')
|
||||
bl.class('PlayerData' , 'ShapeBaseData')
|
||||
bl.class('StaticShapeData' , 'ShapeBaseData')
|
||||
bl.class('VehicleData' , 'ShapeBaseData')
|
||||
bl.class('FlyingVehicleData' , 'VehicleData')
|
||||
bl.class('WheeledVehicleData', 'VehicleData')
|
||||
bl.class('DebrisData' , 'GameBaseData')
|
||||
bl.class('ProjectileData' , 'GameBaseData')
|
||||
bl.class('ShapeBaseImageData' , 'GameBaseData')
|
||||
bl.class('TriggerData' , 'GameBaseData')
|
||||
bl.class('ExplosionData' , 'GameBaseData')
|
||||
bl.class('fxLightData' , 'GameBaseData')
|
||||
bl.class('LightningData' , 'GameBaseData')
|
||||
bl.class('ParticleEmitterNodeData', 'GameBaseData')
|
||||
bl.class('SplashData' , 'GameBaseData')
|
||||
bl.class('fxDTSBrickData' , 'GameBaseData')
|
||||
bl.class('ParticleEmitterData' , 'GameBaseData')
|
||||
bl.class('WheeledVehicleTire' , 'SimDataBlock')
|
||||
bl.class('WheeledVehicleSpring' , 'SimDataBlock')
|
||||
bl.class('TSShapeConstructor' , 'SimDataBlock')
|
||||
bl.class('AudioProfile' , 'SimDataBlock')
|
||||
bl.class('ParticleData' , 'SimDataBlock')
|
||||
bl.class('MaterialPropertyMap', 'SimObject')
|
||||
bl.class('NetObject', 'SimObject')
|
||||
bl.class('SceneObject', 'NetObject')
|
||||
bl.class('GameBase', 'SceneObject')
|
||||
bl.class('ShapeBase', 'GameBase')
|
||||
bl.class('MissionMarker', 'ShapeBase')
|
||||
bl.class('SpawnSphere' , 'MissionMarker')
|
||||
bl.class('VehicleSpawnMarker', 'MissionMarker')
|
||||
bl.class('Waypoint' , 'MissionMarker')
|
||||
bl.class('StaticShape' , 'ShapeBase')
|
||||
bl.class('ScopeAlwaysShape', 'StaticShape')
|
||||
bl.class('Player' , 'ShapeBase')
|
||||
bl.class('AIPlayer', 'Player')
|
||||
bl.class('Camera' , 'ShapeBase')
|
||||
bl.class('Item' , 'ShapeBase')
|
||||
bl.class('PathCamera' , 'ShapeBase')
|
||||
bl.class('Vehicle' , 'ShapeBase')
|
||||
bl.class('FlyingVehicle' , 'Vehicle')
|
||||
bl.class('WheeledVehicle', 'Vehicle')
|
||||
bl.class('Explosion' , 'GameBase')
|
||||
bl.class('Splash' , 'GameBase')
|
||||
bl.class('Debris' , 'GameBase')
|
||||
bl.class('Projectile' , 'GameBase')
|
||||
bl.class('Trigger' , 'GameBase')
|
||||
bl.class('fxLight' , 'GameBase')
|
||||
bl.class('Lightning' , 'GameBase')
|
||||
bl.class('ParticleEmitterNode', 'GameBase')
|
||||
bl.class('ParticleEmitter' , 'GameBase')
|
||||
bl.class('Precipitation' , 'GameBase')
|
||||
bl.class('TSStatic' , 'SceneObject')
|
||||
bl.class('VehicleBlocker', 'SceneObject')
|
||||
bl.class('Marker' , 'SceneObject')
|
||||
bl.class('AudioEmitter' , 'SceneObject')
|
||||
bl.class('PhysicalZone' , 'SceneObject')
|
||||
bl.class('fxDayCycle' , 'SceneObject')
|
||||
bl.class('fxDTSBrick' , 'SceneObject')
|
||||
bl.class('fxPlane' , 'SceneObject')
|
||||
bl.class('fxSunLight' , 'SceneObject')
|
||||
bl.class('Sky' , 'SceneObject')
|
||||
bl.class('SceneRoot' , 'SceneObject')
|
||||
bl.class('Sun', 'NetObject')
|
||||
bl.class('GuiCursor', 'SimObject')
|
||||
bl.class('ConsoleLogger' , 'SimObject')
|
||||
bl.class('QuotaObject' , 'SimObject')
|
||||
bl.class('FileObject' , 'SimObject')
|
||||
bl.class('BanList' , 'SimObject')
|
||||
bl.class('GuiControlProfile', 'SimObject')
|
||||
bl.class('MessageVector' , 'SimObject')
|
||||
bl.class('ActionMap' , 'SimObject')
|
||||
bl.class('ScriptObject', 'SimObject')
|
||||
bl.class('SimSet', 'SimObject')
|
||||
bl.class('SimGroup', 'SimSet')
|
||||
bl.class('GuiControl', 'SimGroup')
|
||||
bl.class('GuiTextCtrl', 'GuiControl')
|
||||
bl.class('GuiSwatchCtrl', 'GuiControl')
|
||||
bl.class('GuiButtonBaseCtrl', 'GuiControl')
|
||||
bl.class('GuiArrayCtrl', 'GuiControl')
|
||||
bl.class('GuiScrollCtrl', 'GuiControl')
|
||||
bl.class('GuiMouseEventCtrl', 'GuiControl')
|
||||
bl.class('GuiProgressCtrl', 'GuiControl')
|
||||
bl.class('GuiSliderCtrl', 'GuiControl')
|
||||
bl.class('GuiConsoleTextCtrl', 'GuiControl')
|
||||
bl.class('GuiTSCtrl', 'GuiControl')
|
||||
bl.class('GuiObjectView', 'GuiTSCtrl')
|
||||
bl.class('GameTSCtrl', 'GuiTSCtrl')
|
||||
bl.class('EditTSCtrl', 'GuiTSCtrl')
|
||||
bl.class('GuiPlayerView', 'GuiTSCtrl')
|
||||
bl.class('GuiShapeNameHud', 'GuiControl')
|
||||
bl.class('GuiHealthBarHud', 'GuiControl')
|
||||
bl.class('GuiGraphCtrl', 'GuiControl')
|
||||
bl.class('GuiInspector', 'GuiControl')
|
||||
bl.class('GuiChunkedBitmapCtrl', 'GuiControl')
|
||||
bl.class('GuiInputCtrl', 'GuiControl')
|
||||
bl.class('GuiNoMouseCtrl', 'GuiControl')
|
||||
bl.class('GuiBitmapBorderCtrl', 'GuiControl')
|
||||
bl.class('GuiBackgroundCtrl', 'GuiControl')
|
||||
bl.class('GuiEditorRuler', 'GuiControl')
|
||||
bl.class('GuiClockHud', 'GuiControl')
|
||||
bl.class('GuiEditCtrl', 'GuiControl')
|
||||
bl.class('GuiFilterCtrl', 'GuiControl')
|
||||
bl.class('GuiFrameSetCtrl', 'GuiControl')
|
||||
bl.class('GuiMenuBar', 'GuiControl')
|
||||
bl.class('GuiMessageVectorCtrl', 'GuiControl')
|
||||
bl.class('GuiBitmapCtrl', 'GuiControl')
|
||||
bl.class('GuiCrossHairHud', 'GuiBitmapCtrl')
|
||||
bl.class('ScriptGroup', 'SimGroup')
|
||||
bl.class('NetConnection', 'SimGroup')
|
||||
bl.class('GameConnection', 'NetConnection')
|
||||
bl.class('Path', 'SimGroup')
|
||||
bl.class('TCPObject', 'SimObject')
|
||||
bl.class('SOCKObject', 'TCPObject')
|
||||
bl.class('HTTPObject', 'TCPObject')
|
||||
bl.class('SimDataBlock', 'SimObject')
|
||||
bl.class('AudioEnvironment', 'SimDataBlock')
|
||||
bl.class('AudioSampleEnvironment', 'SimDataBlock')
|
||||
bl.class('AudioDescription', 'SimDataBlock')
|
||||
bl.class('GameBaseData', 'SimDataBlock')
|
||||
bl.class('ShapeBaseData', 'GameBaseData')
|
||||
bl.class('CameraData', 'ShapeBaseData')
|
||||
bl.class('ItemData', 'ShapeBaseData')
|
||||
bl.class('MissionMarkerData', 'ShapeBaseData')
|
||||
bl.class('PathCameraData', 'ShapeBaseData')
|
||||
bl.class('PlayerData', 'ShapeBaseData')
|
||||
bl.class('StaticShapeData', 'ShapeBaseData')
|
||||
bl.class('VehicleData', 'ShapeBaseData')
|
||||
bl.class('FlyingVehicleData', 'VehicleData')
|
||||
bl.class('WheeledVehicleData', 'VehicleData')
|
||||
bl.class('DebrisData', 'GameBaseData')
|
||||
bl.class('ProjectileData', 'GameBaseData')
|
||||
bl.class('ShapeBaseImageData', 'GameBaseData')
|
||||
bl.class('TriggerData', 'GameBaseData')
|
||||
bl.class('ExplosionData', 'GameBaseData')
|
||||
bl.class('fxLightData', 'GameBaseData')
|
||||
bl.class('LightningData', 'GameBaseData')
|
||||
bl.class('ParticleEmitterNodeData', 'GameBaseData')
|
||||
bl.class('SplashData', 'GameBaseData')
|
||||
bl.class('fxDTSBrickData', 'GameBaseData')
|
||||
bl.class('ParticleEmitterData', 'GameBaseData')
|
||||
bl.class('WheeledVehicleTire', 'SimDataBlock')
|
||||
bl.class('WheeledVehicleSpring', 'SimDataBlock')
|
||||
bl.class('TSShapeConstructor', 'SimDataBlock')
|
||||
bl.class('AudioProfile', 'SimDataBlock')
|
||||
bl.class('ParticleData', 'SimDataBlock')
|
||||
bl.class('MaterialPropertyMap', 'SimObject')
|
||||
bl.class('NetObject', 'SimObject')
|
||||
bl.class('SceneObject', 'NetObject')
|
||||
bl.class('GameBase', 'SceneObject')
|
||||
bl.class('ShapeBase', 'GameBase')
|
||||
bl.class('MissionMarker', 'ShapeBase')
|
||||
bl.class('SpawnSphere', 'MissionMarker')
|
||||
bl.class('VehicleSpawnMarker', 'MissionMarker')
|
||||
bl.class('Waypoint', 'MissionMarker')
|
||||
bl.class('StaticShape', 'ShapeBase')
|
||||
bl.class('ScopeAlwaysShape', 'StaticShape')
|
||||
bl.class('Player', 'ShapeBase')
|
||||
bl.class('AIPlayer', 'Player')
|
||||
bl.class('Camera', 'ShapeBase')
|
||||
bl.class('Item', 'ShapeBase')
|
||||
bl.class('PathCamera', 'ShapeBase')
|
||||
bl.class('Vehicle', 'ShapeBase')
|
||||
bl.class('FlyingVehicle', 'Vehicle')
|
||||
bl.class('WheeledVehicle', 'Vehicle')
|
||||
bl.class('Explosion', 'GameBase')
|
||||
bl.class('Splash', 'GameBase')
|
||||
bl.class('Debris', 'GameBase')
|
||||
bl.class('Projectile', 'GameBase')
|
||||
bl.class('Trigger', 'GameBase')
|
||||
bl.class('fxLight', 'GameBase')
|
||||
bl.class('Lightning', 'GameBase')
|
||||
bl.class('ParticleEmitterNode', 'GameBase')
|
||||
bl.class('ParticleEmitter', 'GameBase')
|
||||
bl.class('Precipitation', 'GameBase')
|
||||
bl.class('TSStatic', 'SceneObject')
|
||||
bl.class('VehicleBlocker', 'SceneObject')
|
||||
bl.class('Marker', 'SceneObject')
|
||||
bl.class('AudioEmitter', 'SceneObject')
|
||||
bl.class('PhysicalZone', 'SceneObject')
|
||||
bl.class('fxDayCycle', 'SceneObject')
|
||||
bl.class('fxDTSBrick', 'SceneObject')
|
||||
bl.class('fxPlane', 'SceneObject')
|
||||
bl.class('fxSunLight', 'SceneObject')
|
||||
bl.class('Sky', 'SceneObject')
|
||||
bl.class('SceneRoot', 'SceneObject')
|
||||
bl.class('Sun', 'NetObject')
|
||||
bl.class('GuiCursor', 'SimObject')
|
||||
bl.class('ConsoleLogger', 'SimObject')
|
||||
bl.class('QuotaObject', 'SimObject')
|
||||
bl.class('FileObject', 'SimObject')
|
||||
bl.class('BanList', 'SimObject')
|
||||
bl.class('GuiControlProfile', 'SimObject')
|
||||
bl.class('MessageVector', 'SimObject')
|
||||
bl.class('ActionMap', 'SimObject')
|
||||
|
||||
-- Auto-generated from game scripts
|
||||
bl.type('ActionMap::blockBind:1', 'object')
|
||||
|
||||
1837
src/util/libbl.lua
1837
src/util/libbl.lua
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
|
||||
-- This Lua code provides some built-in utilities for writing Lua add-ons
|
||||
-- It is eval'd automatically once BLLua3 has loaded the TS API and environment
|
||||
-- It only has access to the sandboxed lua environment, just like user code.
|
||||
@@ -7,8 +6,11 @@ ts = _bllua_ts
|
||||
|
||||
-- Provide limited OS functions
|
||||
os = os or {}
|
||||
function os.time() return math.floor(tonumber(_bllua_ts.call('getSimTime'))/1000) end
|
||||
function os.clock() return tonumber(_bllua_ts.call('getSimTime'))/1000 end
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function os.time() return math.floor(tonumber(_bllua_ts.call('getSimTime')) / 1000) end
|
||||
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function os.clock() return tonumber(_bllua_ts.call('getSimTime')) / 1000 end
|
||||
|
||||
-- Virtual file class, emulating a file object as returned by io.open
|
||||
-- Used to wrap io.open to allow reading from zips (using TS)
|
||||
@@ -16,141 +18,154 @@ function os.clock() return tonumber(_bllua_ts.call('getSimTime'))/1000 end
|
||||
-- Can't read nulls, can't distinguish between CRLF and LF.
|
||||
-- Todo someday: actually read the zip in lua?
|
||||
local file_meta = {
|
||||
read = function(file, mode)
|
||||
file:_init()
|
||||
if not file or type(file)~='table' or not file._is_file then error('File:read: Not a file', 2) end
|
||||
if file._is_open ~= true then error('File:read: File is closed', 2) end
|
||||
if mode=='*n' then
|
||||
local ws, n = file.data:match('^([ \t\r\n]*)([0-9%.%-e]+)', file.pos)
|
||||
if n then
|
||||
file.pos = file.pos + #ws + #n
|
||||
return n
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif mode=='*a' then
|
||||
local d = file.data:sub(file.pos, #file.data)
|
||||
file.pos = #file.data + 1
|
||||
return d
|
||||
elseif mode=='*l' then
|
||||
local l, ws = file.data:match('^([^\r\n]*)(\r?\n)', file.pos)
|
||||
if not l then
|
||||
l = file.data:match('^([^\r\n]*)$', file.pos); ws = '';
|
||||
if l=='' then return nil end
|
||||
end
|
||||
if l then
|
||||
file.pos = file.pos + #l + #ws
|
||||
return l
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif type(mode)=='number' then
|
||||
local d = file.data:sub(file.pos, file.pos+mode)
|
||||
file.pos = file.pos + #d
|
||||
return d
|
||||
else
|
||||
error('File:read: Invalid mode \''..mode..'\'', 2)
|
||||
end
|
||||
end,
|
||||
lines = function(file)
|
||||
file:_init()
|
||||
return function()
|
||||
return file:read('*l')
|
||||
end
|
||||
end,
|
||||
close = function(file)
|
||||
if not file._is_open then error('File:close: File is not open', 2) end
|
||||
file._is_open = false
|
||||
end,
|
||||
__index = function(f, k) return rawget(f, k) or getmetatable(f)[k] end,
|
||||
_init = function(f)
|
||||
if not f.data then
|
||||
f.data = _bllua_ts.call('_bllua_ReadEntireFile', f.filename)
|
||||
end
|
||||
end,
|
||||
read = function(file, mode)
|
||||
file:_init()
|
||||
if not file or type(file) ~= 'table' or not file._is_file then error('File:read: Not a file', 2) end
|
||||
if file._is_open ~= true then error('File:read: File is closed', 2) end
|
||||
if mode == '*n' then
|
||||
local ws, n = file.data:match('^([ \t\r\n]*)([0-9%.%-e]+)', file.pos)
|
||||
if n then
|
||||
file.pos = file.pos + #ws + #n
|
||||
return n
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif mode == '*a' then
|
||||
local d = file.data:sub(file.pos, #file.data)
|
||||
file.pos = #file.data + 1
|
||||
return d
|
||||
elseif mode == '*l' then
|
||||
local l, ws = file.data:match('^([^\r\n]*)(\r?\n)', file.pos)
|
||||
if not l then
|
||||
l = file.data:match('^([^\r\n]*)$', file.pos); ws = '';
|
||||
if l == '' then return nil end
|
||||
end
|
||||
if l then
|
||||
file.pos = file.pos + #l + #ws
|
||||
return l
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif type(mode) == 'number' then
|
||||
local d = file.data:sub(file.pos, file.pos + mode)
|
||||
file.pos = file.pos + #d
|
||||
return d
|
||||
else
|
||||
error('File:read: Invalid mode \'' .. mode .. '\'', 2)
|
||||
end
|
||||
end,
|
||||
lines = function(file)
|
||||
file:_init()
|
||||
return function()
|
||||
return file:read('*l')
|
||||
end
|
||||
end,
|
||||
close = function(file)
|
||||
if not file._is_open then error('File:close: File is not open', 2) end
|
||||
file._is_open = false
|
||||
end,
|
||||
__index = function(f, k) return rawget(f, k) or getmetatable(f)[k] end,
|
||||
_init = function(f)
|
||||
if not f.data then
|
||||
f.data = _bllua_ts.call('_bllua_ReadEntireFile', f.filename)
|
||||
end
|
||||
end,
|
||||
}
|
||||
local function new_file_obj(fn)
|
||||
local file = {
|
||||
_is_file = true,
|
||||
_is_open = true,
|
||||
pos = 1,
|
||||
__index = file_meta.__index,
|
||||
filename = fn,
|
||||
data = nil,
|
||||
}
|
||||
setmetatable(file, file_meta)
|
||||
return file
|
||||
local file = {
|
||||
_is_file = true,
|
||||
_is_open = true,
|
||||
pos = 1,
|
||||
__index = file_meta.__index,
|
||||
filename = fn,
|
||||
data = nil,
|
||||
}
|
||||
setmetatable(file, file_meta)
|
||||
return file
|
||||
end
|
||||
|
||||
local function tflip(t) local u = {}; for _, n in ipairs(t) do u[n] = true end; return u; end
|
||||
local allowed_zip_dirs = tflip{
|
||||
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
||||
local function tflip(t)
|
||||
local u = {}; for _, n in ipairs(t) do u[n] = true end; return u;
|
||||
end
|
||||
local allowed_zip_dirs = tflip {
|
||||
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
||||
}
|
||||
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
|
||||
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, '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
|
||||
|
||||
if mode~=nil and mode~='r' and mode~='rb' then
|
||||
return nil, 'Files in zips can only be opened in read mode' end
|
||||
|
||||
-- return a temp lua file object with the data
|
||||
local fi = new_file_obj(fn)
|
||||
return fi
|
||||
-- if file exists, use original mode
|
||||
local res, err = _bllua_io_open(fn, mode)
|
||||
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, '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
|
||||
|
||||
if mode ~= nil and mode ~= 'r' and mode ~= 'rb' then
|
||||
return nil, 'Files in zips can only be opened in read mode'
|
||||
end
|
||||
|
||||
-- return a temp lua file object with the data
|
||||
local fi = new_file_obj(fn)
|
||||
return fi
|
||||
end
|
||||
|
||||
io = io or {}
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function io.open(fn, mode, errn)
|
||||
errn = errn or 1
|
||||
|
||||
-- try to open the file with relative path, otherwise use absolute path
|
||||
local curfn = debug.getfilename(errn + 1) or _bllua_ts.getvar('Con::File')
|
||||
if curfn == '' then curfn = nil end
|
||||
if fn:find('^%.') then
|
||||
local relfn = curfn and fn:find('^%./') and
|
||||
curfn:gsub('[^/]+$', '')..fn:gsub('^%./', '')
|
||||
if relfn then
|
||||
local fi, err = io_open_absolute(relfn, mode)
|
||||
return fi, err, relfn
|
||||
else
|
||||
return nil, 'Invalid path', fn
|
||||
end
|
||||
else
|
||||
local fi, err = io_open_absolute(fn, mode)
|
||||
return fi, err, fn
|
||||
end
|
||||
errn = errn or 1
|
||||
|
||||
-- try to open the file with relative path, otherwise use absolute path
|
||||
local curfn = debug.getfilename(errn + 1) or _bllua_ts.getvar('Con::File')
|
||||
if curfn == '' then curfn = nil end
|
||||
if fn:find('^%.') then
|
||||
local relfn = curfn and fn:find('^%./') and
|
||||
curfn:gsub('[^/]+$', '') .. fn:gsub('^%./', '')
|
||||
if relfn then
|
||||
local fi, err = io_open_absolute(relfn, mode)
|
||||
return fi, err, relfn
|
||||
else
|
||||
return nil, 'Invalid path', fn
|
||||
end
|
||||
else
|
||||
local fi, err = io_open_absolute(fn, mode)
|
||||
return fi, err, fn
|
||||
end
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function io.lines(fn)
|
||||
local fi, err, fn2 = io.open(fn, nil, 2)
|
||||
if not fi then error('Error opening file \''..fn2..'\': '..err, 2) end
|
||||
return fi:lines()
|
||||
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
|
||||
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
function io.type(f)
|
||||
if type(f)=='table' and f._is_file then
|
||||
return f._is_open and 'file' or 'closed file'
|
||||
else
|
||||
return _bllua_io_type(f)
|
||||
end
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
if type(f) == 'table' and f._is_file then
|
||||
---@diagnostic disable-next-line: undefined-field
|
||||
return f._is_open and 'file' or 'closed file'
|
||||
else
|
||||
return _bllua_io_type(f)
|
||||
end
|
||||
end
|
||||
|
||||
-- provide dofile
|
||||
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 \''..fn2..'\': '..err, errn+1) end
|
||||
|
||||
print('Executing '..fn2)
|
||||
local text = fi:read('*a')
|
||||
fi:close()
|
||||
return assert(loadstring('--[['..fn2..']]'..text))()
|
||||
errn = errn or 1
|
||||
|
||||
local fi, err, fn2 = io.open(fn, 'r', errn + 1)
|
||||
if not fi then error('Error executing file \'' .. fn2 .. '\': ' .. err, errn + 1) end
|
||||
|
||||
print('Executing ' .. fn2)
|
||||
local text = fi:read('*a')
|
||||
fi:close()
|
||||
return assert(loadstring('--[[' .. fn2 .. ']]' .. text))()
|
||||
end
|
||||
|
||||
-- provide require (just a wrapper for dofile)
|
||||
@@ -159,57 +174,58 @@ end
|
||||
-- blockland directory
|
||||
-- current add-on
|
||||
local function file_exists(fn, errn)
|
||||
local fi, err, fn2 = io.open(fn, 'r', errn+1)
|
||||
if fi then
|
||||
fi:close()
|
||||
return fn2
|
||||
else
|
||||
return nil
|
||||
end
|
||||
local fi, err, fn2 = io.open(fn, 'r', errn + 1)
|
||||
if fi then
|
||||
fi:close()
|
||||
return fn2
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
local require_memo = {}
|
||||
function require(mod)
|
||||
if require_memo[mod] then return unpack(require_memo[mod]) end
|
||||
local fp = mod:gsub('%.', '/')
|
||||
local fns = {
|
||||
'./'..fp..'.lua', -- local file
|
||||
'./'..fp..'/init.lua', -- local library
|
||||
fp..'.lua', -- global file
|
||||
fp..'/init.lua', -- global library
|
||||
}
|
||||
if fp:lower():find('^add-ons/') then
|
||||
local addonpath = fp:lower():match('^add-ons/[^/]+')..'/'
|
||||
table.insert(fns, addonpath..fp..'.lua') -- add-on file
|
||||
table.insert(fns, addonpath..fp..'/init.lua') -- add-on library
|
||||
end
|
||||
for _,fn in ipairs(fns) do
|
||||
local fne = file_exists(fn, 2)
|
||||
if fne then
|
||||
local res = {dofile(fne, 2)}
|
||||
require_memo[mod] = res
|
||||
return unpack(res)
|
||||
end
|
||||
end
|
||||
return _bllua_requiresecure(mod)
|
||||
if require_memo[mod] then return unpack(require_memo[mod]) end
|
||||
local fp = mod:gsub('%.', '/')
|
||||
local fns = {
|
||||
'./' .. fp .. '.lua', -- local file
|
||||
'./' .. fp .. '/init.lua', -- local library
|
||||
fp .. '.lua', -- global file
|
||||
fp .. '/init.lua', -- global library
|
||||
}
|
||||
if fp:lower():find('^add-ons/') then
|
||||
local addonpath = fp:lower():match('^add-ons/[^/]+') .. '/'
|
||||
table.insert(fns, addonpath .. fp .. '.lua') -- add-on file
|
||||
table.insert(fns, addonpath .. fp .. '/init.lua') -- add-on library
|
||||
end
|
||||
for _, fn in ipairs(fns) do
|
||||
local fne = file_exists(fn, 2)
|
||||
if fne then
|
||||
local res = { dofile(fne, 2) }
|
||||
require_memo[mod] = res
|
||||
return unpack(res)
|
||||
end
|
||||
end
|
||||
return _bllua_requiresecure(mod)
|
||||
end
|
||||
|
||||
local function isValidCode(code)
|
||||
local f,e = loadstring(code)
|
||||
return f~=nil
|
||||
local f, e = loadstring(code)
|
||||
return f ~= nil
|
||||
end
|
||||
function _bllua_smarteval(code)
|
||||
if (not code:find('^print%(')) and isValidCode('print('..code..')') then
|
||||
code = 'print('..code..')' end
|
||||
local f,e = loadstring(code)
|
||||
if f then
|
||||
return f()
|
||||
else
|
||||
print(e)
|
||||
end
|
||||
if (not code:find('^print%(')) and isValidCode('print(' .. code .. ')') then
|
||||
code = 'print(' .. code .. ')'
|
||||
end
|
||||
local f, e = loadstring(code)
|
||||
if f then
|
||||
return f()
|
||||
else
|
||||
print(e)
|
||||
end
|
||||
end
|
||||
|
||||
function ts.setvar(name, val)
|
||||
_bllua_ts.call('_bllua_set_var', name, val)
|
||||
_bllua_ts.call('_bllua_set_var', name, val)
|
||||
end
|
||||
|
||||
_bllua_ts.call('echo', ' Executed libts-lua.lua')
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
-- todo
|
||||
-- Matrix class with math operators
|
||||
|
||||
|
||||
590
src/util/std.lua
590
src/util/std.lua
@@ -1,370 +1,398 @@
|
||||
|
||||
-- Basic functionality that should be standard in Lua
|
||||
|
||||
|
||||
-- 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
|
||||
function table.map(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(unpack(args))
|
||||
end
|
||||
return u
|
||||
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(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
|
||||
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
|
||||
|
||||
function table.map_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(unpack(args))
|
||||
end
|
||||
return u
|
||||
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(unpack(args))
|
||||
end
|
||||
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
|
||||
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 = {}
|
||||
for k,v in pairs(t) do u[v] = k end
|
||||
return u
|
||||
local u = {}
|
||||
for k, v in pairs(t) do u[v] = k end
|
||||
return u
|
||||
end
|
||||
|
||||
-- Reverse a list
|
||||
function table.reverse(l)
|
||||
local m = {}
|
||||
for i=1,#l do m[#l-i+1] = l[i] end
|
||||
return m
|
||||
local m = {}
|
||||
for i = 1, #l do m[#l - i + 1] = l[i] end
|
||||
return m
|
||||
end
|
||||
|
||||
-- Whether a table is a list/array (has only monotonic integer keys)
|
||||
function table.islist(t)
|
||||
local n = 0
|
||||
for i,_ in pairs(t) do
|
||||
if type(i)~='number' or i%1~=0 then return false end
|
||||
n = n+1
|
||||
end
|
||||
return n==#t
|
||||
local n = 0
|
||||
for i, _ in pairs(t) do
|
||||
if type(i) ~= 'number' or i % 1 ~= 0 then return false end
|
||||
n = n + 1
|
||||
end
|
||||
return n == #t
|
||||
end
|
||||
|
||||
-- Append contents of other tables to first table
|
||||
function table.append(t, ...)
|
||||
local a = {...}
|
||||
for _,u in ipairs(a) do
|
||||
for _,v in ipairs(u) do table.insert(t,v) end
|
||||
end
|
||||
return t
|
||||
local a = { ... }
|
||||
for _, u in ipairs(a) do
|
||||
for _, v in ipairs(u) do table.insert(t, v) end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
-- Create a new table containing all keys from any number of tables
|
||||
-- latter tables in the arg list override prior ones
|
||||
-- overlaps, NOT appends, integer keys
|
||||
function table.join(...)
|
||||
local ts = {...}
|
||||
local w = {}
|
||||
for _,t in ipairs(ts) do
|
||||
for k,v in pairs(t) do w[k] = v end
|
||||
end
|
||||
return w
|
||||
local ts = { ... }
|
||||
local w = {}
|
||||
for _, t in ipairs(ts) do
|
||||
for k, v in pairs(t) do w[k] = v end
|
||||
end
|
||||
return w
|
||||
end
|
||||
|
||||
-- Whether a table contains a certain value in any key
|
||||
function table.contains(t,s)
|
||||
for _,v in pairs(t) do
|
||||
if v==s then return true end
|
||||
end
|
||||
return false
|
||||
function table.contains(t, s)
|
||||
for _, v in pairs(t) do
|
||||
if v == s then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function table.contains_list(t,s)
|
||||
for _,v in ipairs(t) do
|
||||
if v==s then return true end
|
||||
end
|
||||
return false
|
||||
|
||||
function table.contains_list(t, s)
|
||||
for _, v in ipairs(t) do
|
||||
if v == s then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Copy a table to another table
|
||||
function table.copy(t)
|
||||
local u = {}
|
||||
for k,v in pairs(t) do u[k] = v end
|
||||
return u
|
||||
local u = {}
|
||||
for k, v in pairs(t) do u[k] = v end
|
||||
return u
|
||||
end
|
||||
|
||||
function table.copy_list(l)
|
||||
local m = {}
|
||||
for i,v in ipairs(l) do m[i] = v end
|
||||
return m
|
||||
local m = {}
|
||||
for i, v in ipairs(l) do m[i] = v end
|
||||
return m
|
||||
end
|
||||
|
||||
-- Sort a table in a new copy
|
||||
function table.sortcopy(t, f)
|
||||
local u = table.copy_list(t)
|
||||
table.sort(u, f)
|
||||
return u
|
||||
local u = table.copy_list(t)
|
||||
table.sort(u, f)
|
||||
return u
|
||||
end
|
||||
|
||||
-- Remove a value from a table
|
||||
function table.removevalue(t, r)
|
||||
local rem = {}
|
||||
for k,v in pairs(t) do
|
||||
if v==r then table.insert(rem, k) end
|
||||
end
|
||||
for _,k in ipairs(rem) do t[k] = nil end
|
||||
local rem = {}
|
||||
for k, v in pairs(t) do
|
||||
if v == r then table.insert(rem, k) end
|
||||
end
|
||||
for _, k in ipairs(rem) do t[k] = nil end
|
||||
end
|
||||
|
||||
function table.removevalue_list(t, r)
|
||||
for i = #t, 1, -1 do
|
||||
if t[i]==r then
|
||||
table.remove(t, i)
|
||||
end
|
||||
end
|
||||
for i = #t, 1, -1 do
|
||||
if t[i] == r then
|
||||
table.remove(t, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Export tables into formatted executable strings
|
||||
local function tabs(tabLevel)
|
||||
return (' '):rep(tabLevel)
|
||||
return (' '):rep(tabLevel)
|
||||
end
|
||||
local valueToString
|
||||
local function tableToString(t, tabLevel, seen)
|
||||
if type(t)~='table' or (getmetatable(t) and getmetatable(t).__tostring) then
|
||||
return tostring(t)
|
||||
elseif table.islist(t) then
|
||||
if #t==0 then
|
||||
return '{}'
|
||||
else
|
||||
local strs = {}
|
||||
local containsTables = false
|
||||
for _,v in ipairs(t) do
|
||||
if type(v)=='table' then containsTables = true end
|
||||
table.insert(strs, valueToString(v, tabLevel+1, seen)..',')
|
||||
end
|
||||
if containsTables or #t>3 then
|
||||
return '{\n'..tabs(tabLevel+1)
|
||||
..table.concat(strs, '\n'..tabs(tabLevel+1))
|
||||
..'\n'..tabs(tabLevel)..'}'
|
||||
else
|
||||
return '{ '..table.concat(strs, ' ')..' }'
|
||||
end
|
||||
end
|
||||
else
|
||||
local containsNonStringKeys = false
|
||||
for k,v in pairs(t) do
|
||||
if type(k)~='string' or k:find('[^a-zA-Z0-9_]') then
|
||||
containsNonStringKeys = true
|
||||
elseif type(k)=='table' then
|
||||
error('table.tostring: table contains a table as key, cannot serialize')
|
||||
end
|
||||
end
|
||||
local strs = {}
|
||||
if containsNonStringKeys then
|
||||
for k,v in pairs(t) do
|
||||
table.insert(strs, '\n'..tabs(tabLevel+1)
|
||||
..'['..valueToString(k, tabLevel+1, seen)..'] = '
|
||||
..valueToString(v, tabLevel+1, seen)..',')
|
||||
end
|
||||
else
|
||||
for k,v in pairs(t) do
|
||||
table.insert(strs, '\n'..tabs(tabLevel+1)
|
||||
..k..' = '..valueToString(v, tabLevel+1, seen)..',')
|
||||
end
|
||||
end
|
||||
return '{'..table.concat(strs)..'\n'..tabs(tabLevel)..'}'
|
||||
end
|
||||
if type(t) ~= 'table' or (getmetatable(t) and getmetatable(t).__tostring) then
|
||||
return tostring(t)
|
||||
elseif table.islist(t) then
|
||||
if #t == 0 then
|
||||
return '{}'
|
||||
else
|
||||
local strs = {}
|
||||
local containsTables = false
|
||||
for _, v in ipairs(t) do
|
||||
if type(v) == 'table' then containsTables = true end
|
||||
table.insert(strs, valueToString(v, tabLevel + 1, seen) .. ',')
|
||||
end
|
||||
if containsTables or #t > 3 then
|
||||
return '{\n' .. tabs(tabLevel + 1)
|
||||
.. table.concat(strs, '\n' .. tabs(tabLevel + 1))
|
||||
.. '\n' .. tabs(tabLevel) .. '}'
|
||||
else
|
||||
return '{ ' .. table.concat(strs, ' ') .. ' }'
|
||||
end
|
||||
end
|
||||
else
|
||||
local containsNonStringKeys = false
|
||||
for k, v in pairs(t) do
|
||||
if type(k) ~= 'string' or k:find('[^a-zA-Z0-9_]') then
|
||||
containsNonStringKeys = true
|
||||
elseif type(k) == 'table' then
|
||||
error('table.tostring: table contains a table as key, cannot serialize')
|
||||
end
|
||||
end
|
||||
local strs = {}
|
||||
if containsNonStringKeys then
|
||||
for k, v in pairs(t) do
|
||||
table.insert(strs, '\n' .. tabs(tabLevel + 1)
|
||||
.. '[' .. valueToString(k, tabLevel + 1, seen) .. '] = '
|
||||
.. valueToString(v, tabLevel + 1, seen) .. ',')
|
||||
end
|
||||
else
|
||||
for k, v in pairs(t) do
|
||||
table.insert(strs, '\n' .. tabs(tabLevel + 1)
|
||||
.. k .. ' = ' .. valueToString(v, tabLevel + 1, seen) .. ',')
|
||||
end
|
||||
end
|
||||
return '{' .. table.concat(strs) .. '\n' .. tabs(tabLevel) .. '}'
|
||||
end
|
||||
end
|
||||
valueToString = function(v, tabLevel, seen)
|
||||
local t = type(v)
|
||||
if t=='table' then
|
||||
if seen[v] then
|
||||
return 'nil --[[ already seen: '..tostring(v)..' ]]'
|
||||
else
|
||||
seen[v] = true
|
||||
return tableToString(v, tabLevel, seen)
|
||||
end
|
||||
elseif t=='string' then
|
||||
return '\''..string.escape(v)..'\''
|
||||
elseif t=='number' or t=='boolean' then
|
||||
return tostring(v)
|
||||
else
|
||||
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
||||
return 'nil --[[ '..tostring(v)..' ]]'
|
||||
end
|
||||
local t = type(v)
|
||||
if t == 'table' then
|
||||
if seen[v] then
|
||||
return 'nil --[[ already seen: ' .. tostring(v) .. ' ]]'
|
||||
else
|
||||
seen[v] = true
|
||||
return tableToString(v, tabLevel, seen)
|
||||
end
|
||||
elseif t == 'string' then
|
||||
return '\'' .. string.escape(v) .. '\''
|
||||
elseif t == 'number' or t == 'boolean' then
|
||||
return tostring(v)
|
||||
else
|
||||
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
||||
return 'nil --[[ ' .. tostring(v) .. ' ]]'
|
||||
end
|
||||
end
|
||||
function table.tostring(t)
|
||||
return tableToString(t, 0, {})
|
||||
return tableToString(t, 0, {})
|
||||
end
|
||||
|
||||
|
||||
-- String
|
||||
|
||||
-- Split string into table by separator
|
||||
-- or by chars if no separator given
|
||||
-- if regex is not true, sep is treated as a regex pattern
|
||||
function string.split(str, sep, noregex)
|
||||
if type(str)~='string' then
|
||||
error('string.split: argument #1: expected string, got '..type(str), 2) end
|
||||
if sep==nil or sep=='' then
|
||||
local t = {}
|
||||
local ns = #str
|
||||
for x = 1, ns do
|
||||
table.insert(t, str:sub(x, x))
|
||||
end
|
||||
return t
|
||||
elseif type(sep)=='string' then
|
||||
local t = {}
|
||||
if #str>0 then
|
||||
local first = 1
|
||||
while true do
|
||||
local last, newfirst = str:find(sep, first, noregex)
|
||||
if not last then break end
|
||||
table.insert(t, str:sub(first, last-1))
|
||||
first = newfirst+1
|
||||
end
|
||||
table.insert(t, str:sub(first, #str))
|
||||
end
|
||||
return t
|
||||
else
|
||||
error(
|
||||
'string.split: argument #2: expected string or nil, got '..type(sep), 2)
|
||||
end
|
||||
end
|
||||
-- Split string to a list of char bytes
|
||||
function string.bytes(s)
|
||||
local b = {}
|
||||
for i=1,#s do
|
||||
local c = s:sub(i,i)
|
||||
table.insert(b, c:byte())
|
||||
end
|
||||
return b
|
||||
end
|
||||
-- Trim leading and trailing whitespace
|
||||
function string.trim(s, ws)
|
||||
ws = ws or ' \t\r\n'
|
||||
return s:gsub('^['..ws..']+', ''):gsub('['..ws..']+$', '')..''
|
||||
end
|
||||
-- String slicing and searching using [] operator
|
||||
local str_meta = getmetatable('')
|
||||
local str_meta_index_old= str_meta.__index
|
||||
function str_meta.__index(s,k)
|
||||
if type(k)=='string' then
|
||||
return str_meta_index_old[k]
|
||||
elseif type(k)=='number' then
|
||||
if k<0 then k = #s+k+1 end
|
||||
return string.sub(s,k,k)
|
||||
elseif type(k)=='table' then
|
||||
local a = k[1]<0 and (#s+k[1]+1) or k[1]
|
||||
local b = k[2]<0 and (#s+k[2]+1) or k[2]
|
||||
return string.sub(s,a,b)
|
||||
end
|
||||
end
|
||||
-- String iterator
|
||||
function string.chars(s)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i+1
|
||||
if i<=#s then return s:sub(i,i)
|
||||
else return nil end
|
||||
end
|
||||
end
|
||||
-- Escape sequences
|
||||
local defaultEscapes = {
|
||||
['\\'] = '\\\\',
|
||||
['\''] = '\\\'',
|
||||
['\"'] = '\\\"',
|
||||
['\t'] = '\\t',
|
||||
['\r'] = '\\r',
|
||||
['\n'] = '\\n',
|
||||
['\0'] = '\\0',
|
||||
}
|
||||
function string.escape(s, escapes)
|
||||
escapes = escapes or defaultEscapes
|
||||
local t = {}
|
||||
for i=1,#s do
|
||||
local c = s:sub(i,i)
|
||||
table.insert(t, escapes[c] or c)
|
||||
end
|
||||
return table.concat(t)
|
||||
end
|
||||
local defaultEscapeChar = '\\'
|
||||
local defaultUnescapes = {
|
||||
['\\'] = '\\',
|
||||
['\''] = '\'',
|
||||
['\"'] = '\"',
|
||||
['t'] = '\t',
|
||||
['r'] = '\r',
|
||||
['n'] = '\n',
|
||||
['0'] = '\0',
|
||||
}
|
||||
function string.unescape(s, escapeChar, unescapes)
|
||||
escapeChar = escapeChar or defaultEscapeChar
|
||||
unescapes = unescapes or defaultUnescapes
|
||||
local t = {}
|
||||
local inEscape = false
|
||||
for i=1,#s do
|
||||
local c = s:sub(i,i)
|
||||
if inEscape then
|
||||
table.insert(t, unescapes[c]
|
||||
or error('string.unescape: invalid escape sequence: \''
|
||||
..escapeChar..c..'\''))
|
||||
elseif c==escapeChar then
|
||||
inEscape = true
|
||||
else
|
||||
table.insert(t, c)
|
||||
end
|
||||
end
|
||||
return table.concat(t)
|
||||
if type(str) ~= 'string' then
|
||||
error('string.split: argument #1: expected string, got ' .. type(str), 2)
|
||||
end
|
||||
if sep == nil or sep == '' then
|
||||
local t = {}
|
||||
local ns = #str
|
||||
for x = 1, ns do
|
||||
table.insert(t, str:sub(x, x))
|
||||
end
|
||||
return t
|
||||
elseif type(sep) == 'string' then
|
||||
local t = {}
|
||||
if #str > 0 then
|
||||
local first = 1
|
||||
while true do
|
||||
local last, newfirst = str:find(sep, first, noregex)
|
||||
if not last then break end
|
||||
table.insert(t, str:sub(first, last - 1))
|
||||
first = newfirst + 1
|
||||
end
|
||||
table.insert(t, str:sub(first, #str))
|
||||
end
|
||||
return t
|
||||
else
|
||||
error(
|
||||
'string.split: argument #2: expected string or nil, got ' .. type(sep), 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Split string to a list of char bytes
|
||||
function string.bytes(s)
|
||||
local b = {}
|
||||
for i = 1, #s do
|
||||
local c = s:sub(i, i)
|
||||
table.insert(b, c:byte())
|
||||
end
|
||||
return b
|
||||
end
|
||||
|
||||
-- Trim leading and trailing whitespace
|
||||
function string.trim(s, ws)
|
||||
ws = ws or ' \t\r\n'
|
||||
return s:gsub('^[' .. ws .. ']+', ''):gsub('[' .. ws .. ']+$', '') .. ''
|
||||
end
|
||||
|
||||
-- String slicing and searching using [] operator
|
||||
local str_meta = getmetatable('')
|
||||
local str_meta_index_old = str_meta.__index
|
||||
function str_meta.__index(s, k)
|
||||
if type(k) == 'string' then
|
||||
return str_meta_index_old[k]
|
||||
elseif type(k) == 'number' then
|
||||
if k < 0 then k = #s + k + 1 end
|
||||
return string.sub(s, k, k)
|
||||
elseif type(k) == 'table' then
|
||||
local a = k[1] < 0 and (#s + k[1] + 1) or k[1]
|
||||
local b = k[2] < 0 and (#s + k[2] + 1) or k[2]
|
||||
return string.sub(s, a, b)
|
||||
end
|
||||
end
|
||||
|
||||
-- String iterator
|
||||
function string.chars(s)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
if i <= #s then
|
||||
return s:sub(i, i)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Escape sequences
|
||||
local defaultEscapes = {
|
||||
['\\'] = '\\\\',
|
||||
['\''] = '\\\'',
|
||||
['\"'] = '\\\"',
|
||||
['\t'] = '\\t',
|
||||
['\r'] = '\\r',
|
||||
['\n'] = '\\n',
|
||||
['\0'] = '\\0',
|
||||
}
|
||||
function string.escape(s, escapes)
|
||||
escapes = escapes or defaultEscapes
|
||||
local t = {}
|
||||
for i = 1, #s do
|
||||
local c = s:sub(i, i)
|
||||
table.insert(t, escapes[c] or c)
|
||||
end
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
local defaultEscapeChar = '\\'
|
||||
local defaultUnescapes = {
|
||||
['\\'] = '\\',
|
||||
['\''] = '\'',
|
||||
['\"'] = '\"',
|
||||
['t'] = '\t',
|
||||
['r'] = '\r',
|
||||
['n'] = '\n',
|
||||
['0'] = '\0',
|
||||
}
|
||||
function string.unescape(s, escapeChar, unescapes)
|
||||
escapeChar = escapeChar or defaultEscapeChar
|
||||
unescapes = unescapes or defaultUnescapes
|
||||
local t = {}
|
||||
local inEscape = false
|
||||
for i = 1, #s do
|
||||
local c = s:sub(i, i)
|
||||
if inEscape then
|
||||
table.insert(t, unescapes[c]
|
||||
or error('string.unescape: invalid escape sequence: \''
|
||||
.. escapeChar .. c .. '\''))
|
||||
elseif c == escapeChar then
|
||||
inEscape = true
|
||||
else
|
||||
table.insert(t, c)
|
||||
end
|
||||
end
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
-- IO
|
||||
|
||||
io = io or {}
|
||||
-- Read entire file at once, return nil,err if access failed
|
||||
function io.readall(filename)
|
||||
local fi,err = io.open(filename, 'rb')
|
||||
if not fi then return nil,err end
|
||||
local s = fi:read("*a")
|
||||
fi:close()
|
||||
return s
|
||||
end
|
||||
-- Write data to file all at once, return true if success / false,err if failure
|
||||
function io.writeall(filename, data)
|
||||
local fi,err = io.open(filename, 'wb')
|
||||
if not fi then return false,err end
|
||||
fi:write(data)
|
||||
fi:close()
|
||||
return true,nil
|
||||
local fi, err = io.open(filename, 'rb')
|
||||
if not fi then return nil, err end
|
||||
local s = fi:read("*a")
|
||||
fi:close()
|
||||
return s
|
||||
end
|
||||
|
||||
-- Write data to file all at once, return true if success / false,err if failure
|
||||
function io.writeall(filename, data)
|
||||
local fi, err = io.open(filename, 'wb')
|
||||
if not fi then return false, err end
|
||||
fi:write(data)
|
||||
fi:close()
|
||||
return true, nil
|
||||
end
|
||||
|
||||
-- Math
|
||||
|
||||
-- Round
|
||||
function math.round(x)
|
||||
return math.floor(x+0.5)
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
|
||||
-- Mod that accounts for floating point inaccuracy
|
||||
function math.mod(a,b)
|
||||
local m = a%b
|
||||
if m==0 or math.abs(m)<1e-15 or math.abs(m-b)<1e-15 then return 0
|
||||
else return m end
|
||||
function math.mod(a, b)
|
||||
local m = a % b
|
||||
if m == 0 or math.abs(m) < 1e-15 or math.abs(m - b) < 1e-15 then
|
||||
return 0
|
||||
else
|
||||
return m
|
||||
end
|
||||
end
|
||||
|
||||
-- Clamp value between min and max
|
||||
function math.clamp(v, n, x)
|
||||
return math.min(x, math.max(v, n))
|
||||
return math.min(x, math.max(v, n))
|
||||
end
|
||||
|
||||
|
||||
print(' Executed std.lua')
|
||||
|
||||
@@ -1,218 +1,237 @@
|
||||
|
||||
-- Vector math class with operators
|
||||
local vector_meta
|
||||
local vector_new
|
||||
local function vector_check(v, n, name, argn)
|
||||
if not v.__is_vector then
|
||||
error('vector '..name..': argument #'..(argn or 1)
|
||||
..': expected vector, got '..type(v), n+1) end
|
||||
if not v.__is_vector then
|
||||
error('vector ' .. name .. ': argument #' .. (argn or 1)
|
||||
.. ': expected vector, got ' .. type(v), n + 1)
|
||||
end
|
||||
end
|
||||
local function vector_checksamelen(v1, v2, name)
|
||||
vector_check(v1, 3, name, 1)
|
||||
vector_check(v2, 3, name, 2)
|
||||
if #v1~=#v2 then
|
||||
error('vector '..name..': vector lengths do not match (lengths are '
|
||||
..#v1..' and '..#v2..')', 3) end
|
||||
return #v1
|
||||
vector_check(v1, 3, name, 1)
|
||||
vector_check(v2, 3, name, 2)
|
||||
if #v1 ~= #v2 then
|
||||
error('vector ' .. name .. ': vector lengths do not match (lengths are '
|
||||
.. #v1 .. ' and ' .. #v2 .. ')', 3)
|
||||
end
|
||||
return #v1
|
||||
end
|
||||
local function vector_checklen(v1, v2, name, len)
|
||||
vector_check(v1, 3, name, 1)
|
||||
vector_check(v2, 3, name, 2)
|
||||
if #v1~=len or #v2~=len then
|
||||
error('vector '..name..': vector lengths are not '..len..' (lengths are '
|
||||
..#v1..' and '..#v2..')', 3) end
|
||||
vector_check(v1, 3, name, 1)
|
||||
vector_check(v2, 3, name, 2)
|
||||
if #v1 ~= len or #v2 ~= len then
|
||||
error('vector ' .. name .. ': vector lengths are not ' .. len .. ' (lengths are '
|
||||
.. #v1 .. ' and ' .. #v2 .. ')', 3)
|
||||
end
|
||||
end
|
||||
local function vector_opnnn(name, op)
|
||||
return function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, name)
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2[i])
|
||||
end
|
||||
return vector_new(v3)
|
||||
end
|
||||
return function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, name)
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2[i])
|
||||
end
|
||||
return vector_new(v3)
|
||||
end
|
||||
end
|
||||
local function vector_opnxn(name, op)
|
||||
return function(v1, v2)
|
||||
local v1v = type(v1)=='table' and v1.__is_vector
|
||||
local v2v = type(v2)=='table' and v2.__is_vector
|
||||
if v1v and v2v then
|
||||
local len = vector_checksamelen(v1, v2, name)
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2[i])
|
||||
end
|
||||
return vector_new(v3)
|
||||
else
|
||||
if v2v then v1,v2 = v2,v1 end
|
||||
local len = #v1
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2)
|
||||
end
|
||||
return vector_new(v3)
|
||||
end
|
||||
end
|
||||
return function(v1, v2)
|
||||
local v1v = type(v1) == 'table' and v1.__is_vector
|
||||
local v2v = type(v2) == 'table' and v2.__is_vector
|
||||
if v1v and v2v then
|
||||
local len = vector_checksamelen(v1, v2, name)
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2[i])
|
||||
end
|
||||
return vector_new(v3)
|
||||
else
|
||||
if v2v then v1, v2 = v2, v1 end
|
||||
local len = #v1
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
v3[i] = op(v1[i], v2)
|
||||
end
|
||||
return vector_new(v3)
|
||||
end
|
||||
end
|
||||
end
|
||||
local function vector_opn0n(name, op)
|
||||
return function(v1)
|
||||
--vector_check(v1, 1, name)
|
||||
local len = #v1
|
||||
local v2 = {}
|
||||
for i = 1, len do
|
||||
v2[i] = op(v1[i])
|
||||
end
|
||||
return vector_new(v2)
|
||||
end
|
||||
return function(v1)
|
||||
--vector_check(v1, 1, name)
|
||||
local len = #v1
|
||||
local v2 = {}
|
||||
for i = 1, len do
|
||||
v2[i] = op(v1[i])
|
||||
end
|
||||
return vector_new(v2)
|
||||
end
|
||||
end
|
||||
local vector_indices = {x = 1, y = 2, z = 3, w = 4, r = 1, g = 2, b = 3, a = 4}
|
||||
local vector_indices = { x = 1, y = 2, z = 3, w = 4, r = 1, g = 2, b = 3, a = 4 }
|
||||
local vector_meta = {
|
||||
__is_vector = true,
|
||||
__index = function(t, k)
|
||||
if tonumber(k) then return rawget(t, k)
|
||||
elseif vector_indices[k] then return rawget(t, vector_indices[k])
|
||||
else return getmetatable(t)[k]
|
||||
end
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
if tonumber(k) then rawset(t, k, v)
|
||||
elseif vector_indices[k] then rawset(t, vector_indices[k], v)
|
||||
else return
|
||||
end
|
||||
end,
|
||||
__add = vector_opnnn('add', function(x1, x2) return x1+x2 end),
|
||||
__sub = vector_opnnn('sub', function(x1, x2) return x1-x2 end),
|
||||
__mul = vector_opnxn('mul', function(x1, x2) return x1*x2 end),
|
||||
__div = vector_opnxn('div', function(x1, x2) return x1/x2 end),
|
||||
__pow = vector_opnxn('pow', function(x1, x2) return x1^x2 end),
|
||||
__unm = vector_opn0n('inv', function(x1) return -x1 end),
|
||||
__concat = nil,
|
||||
--__len = function(v1) return #v1 end,
|
||||
__len = nil,
|
||||
__eq = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'equals')
|
||||
for i = 1, len do
|
||||
if v1[i]~=v2[i] then return false end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
__lt = nil,
|
||||
__le = nil,
|
||||
__call = nil,
|
||||
abs = vector_opn0n('abs', math.abs),
|
||||
length = function(v1)
|
||||
--vector_check(v1, 2, 'length')
|
||||
local len = #v1
|
||||
local l = 0
|
||||
for i = 1, len do
|
||||
l = l + v1[i]^2
|
||||
end
|
||||
return math.sqrt(l)
|
||||
end,
|
||||
normalize = function(v1)
|
||||
--vector_check(v1, 2, 'normal')
|
||||
local length = v1:length()
|
||||
local len = #v1
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
if length==0 then v3[i] = 0
|
||||
else v3[i] = v1[i]/length end
|
||||
end
|
||||
return vector_new(v3)
|
||||
end,
|
||||
__tostring = function(v1)
|
||||
--vector_check(v1, 2, 'tostring')
|
||||
local st = {}
|
||||
local len = #v1
|
||||
for i = 1, len do
|
||||
table.insert(st, tostring(v1[i]))
|
||||
end
|
||||
return 'vector{ '..table.concat(st, ', ')..' }'
|
||||
end,
|
||||
unpack = function(v1) return unpack(v1) end,
|
||||
floor = vector_opn0n('floor', function(x1) return math.floor(x1) end),
|
||||
ceil = vector_opn0n('ceil' , function(x1) return math.ceil (x1) end),
|
||||
round = vector_opn0n('round', function(x1) return math.floor(x1+0.5) end),
|
||||
dot = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'dot')
|
||||
local x = 0
|
||||
for i = 1, len do
|
||||
x = x + v1[i]*v2[i]
|
||||
end
|
||||
return x
|
||||
end,
|
||||
cross = function(v1, v2)
|
||||
vector_checklen(v1, v2, 'cross', 3)
|
||||
return vector_new{
|
||||
v1[2]*v2[3] - v1[3]*v2[2],
|
||||
v1[3]*v2[1] - v1[1]*v2[3],
|
||||
v1[1]*v2[2] - v1[2]*v2[1],
|
||||
}
|
||||
end,
|
||||
rotateByAngleId = function(v1, r)
|
||||
--vector_check(v1, 2, 'rotate')
|
||||
if type(r)~='number' or r%1~=0 then
|
||||
error('vector rotateByAngleId: invalid rotation '..tostring(r), 2) end
|
||||
r = r%4
|
||||
local v2
|
||||
if r==0 then v2 = vector_new{ v1[1], v1[2], v1[3] }
|
||||
elseif r==1 then v2 = vector_new{ v1[2], -v1[1], v1[3] }
|
||||
elseif r==2 then v2 = vector_new{ -v1[1], -v1[2], v1[3] }
|
||||
elseif r==3 then v2 = vector_new{ -v1[2], v1[1], v1[3] }
|
||||
else error('vector rotateByAngleId: invalid rotation '..r, 2) end
|
||||
return v2
|
||||
end,
|
||||
rotateZ = function(v, r)
|
||||
--vector_check(v, 2, 'rotate2d')
|
||||
if type(r)~='number' then
|
||||
error('vector rotateZ: invalid rotation '..tostring(r), 2) end
|
||||
local len = math.sqrt(v[1]^2 + v[2]^2)
|
||||
local ang = math.atan2(v[2], v[1]) + r
|
||||
local v2 = vector_new{ math.cos(ang)*len, math.sin(ang)*len }
|
||||
return v2
|
||||
end,
|
||||
tsString = function(v)
|
||||
--vector_check(v, 2, 'tsString')
|
||||
return table.concat(v, ' ')
|
||||
end,
|
||||
distance = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'distance')
|
||||
local sum = 0
|
||||
for i=1,len do
|
||||
sum = sum + (v1[i] - v2[i])^2
|
||||
end
|
||||
return math.sqrt(sum)
|
||||
end,
|
||||
copy = function(v)
|
||||
--vector_check(v, 2, 'copy')
|
||||
return vector_new(v)
|
||||
end,
|
||||
__is_vector = true,
|
||||
__index = function(t, k)
|
||||
if tonumber(k) then
|
||||
return rawget(t, k)
|
||||
elseif vector_indices[k] then
|
||||
return rawget(t, vector_indices[k])
|
||||
else
|
||||
return getmetatable(t)[k]
|
||||
end
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
if tonumber(k) then
|
||||
rawset(t, k, v)
|
||||
elseif vector_indices[k] then
|
||||
rawset(t, vector_indices[k], v)
|
||||
else
|
||||
return
|
||||
end
|
||||
end,
|
||||
__add = vector_opnnn('add', function(x1, x2) return x1 + x2 end),
|
||||
__sub = vector_opnnn('sub', function(x1, x2) return x1 - x2 end),
|
||||
__mul = vector_opnxn('mul', function(x1, x2) return x1 * x2 end),
|
||||
__div = vector_opnxn('div', function(x1, x2) return x1 / x2 end),
|
||||
__pow = vector_opnxn('pow', function(x1, x2) return x1 ^ x2 end),
|
||||
__unm = vector_opn0n('inv', function(x1) return -x1 end),
|
||||
__concat = nil,
|
||||
--__len = function(v1) return #v1 end,
|
||||
__len = nil,
|
||||
__eq = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'equals')
|
||||
for i = 1, len do
|
||||
if v1[i] ~= v2[i] then return false end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
__lt = nil,
|
||||
__le = nil,
|
||||
__call = nil,
|
||||
abs = vector_opn0n('abs', math.abs),
|
||||
length = function(v1)
|
||||
--vector_check(v1, 2, 'length')
|
||||
local len = #v1
|
||||
local l = 0
|
||||
for i = 1, len do
|
||||
l = l + v1[i] ^ 2
|
||||
end
|
||||
return math.sqrt(l)
|
||||
end,
|
||||
normalize = function(v1)
|
||||
--vector_check(v1, 2, 'normal')
|
||||
local length = v1:length()
|
||||
local len = #v1
|
||||
local v3 = {}
|
||||
for i = 1, len do
|
||||
if length == 0 then
|
||||
v3[i] = 0
|
||||
else
|
||||
v3[i] = v1[i] / length
|
||||
end
|
||||
end
|
||||
return vector_new(v3)
|
||||
end,
|
||||
__tostring = function(v1)
|
||||
--vector_check(v1, 2, 'tostring')
|
||||
local st = {}
|
||||
local len = #v1
|
||||
for i = 1, len do
|
||||
table.insert(st, tostring(v1[i]))
|
||||
end
|
||||
return 'vector{ ' .. table.concat(st, ', ') .. ' }'
|
||||
end,
|
||||
unpack = function(v1) return unpack(v1) end,
|
||||
floor = vector_opn0n('floor', function(x1) return math.floor(x1) end),
|
||||
ceil = vector_opn0n('ceil', function(x1) return math.ceil(x1) end),
|
||||
round = vector_opn0n('round', function(x1) return math.floor(x1 + 0.5) end),
|
||||
dot = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'dot')
|
||||
local x = 0
|
||||
for i = 1, len do
|
||||
x = x + v1[i] * v2[i]
|
||||
end
|
||||
return x
|
||||
end,
|
||||
cross = function(v1, v2)
|
||||
vector_checklen(v1, v2, 'cross', 3)
|
||||
return vector_new {
|
||||
v1[2] * v2[3] - v1[3] * v2[2],
|
||||
v1[3] * v2[1] - v1[1] * v2[3],
|
||||
v1[1] * v2[2] - v1[2] * v2[1],
|
||||
}
|
||||
end,
|
||||
rotateByAngleId = function(v1, r)
|
||||
--vector_check(v1, 2, 'rotate')
|
||||
if type(r) ~= 'number' or r % 1 ~= 0 then
|
||||
error('vector rotateByAngleId: invalid rotation ' .. tostring(r), 2)
|
||||
end
|
||||
r = r % 4
|
||||
local v2
|
||||
if r == 0 then
|
||||
v2 = vector_new { v1[1], v1[2], v1[3] }
|
||||
elseif r == 1 then
|
||||
v2 = vector_new { v1[2], -v1[1], v1[3] }
|
||||
elseif r == 2 then
|
||||
v2 = vector_new { -v1[1], -v1[2], v1[3] }
|
||||
elseif r == 3 then
|
||||
v2 = vector_new { -v1[2], v1[1], v1[3] }
|
||||
else
|
||||
error('vector rotateByAngleId: invalid rotation ' .. r, 2)
|
||||
end
|
||||
return v2
|
||||
end,
|
||||
rotateZ = function(v, r)
|
||||
--vector_check(v, 2, 'rotate2d')
|
||||
if type(r) ~= 'number' then
|
||||
error('vector rotateZ: invalid rotation ' .. tostring(r), 2)
|
||||
end
|
||||
local len = math.sqrt(v[1] ^ 2 + v[2] ^ 2)
|
||||
local ang = math.atan2(v[2], v[1]) + r
|
||||
local v2 = vector_new { math.cos(ang) * len, math.sin(ang) * len }
|
||||
return v2
|
||||
end,
|
||||
tsString = function(v)
|
||||
--vector_check(v, 2, 'tsString')
|
||||
return table.concat(v, ' ')
|
||||
end,
|
||||
distance = function(v1, v2)
|
||||
local len = vector_checksamelen(v1, v2, 'distance')
|
||||
local sum = 0
|
||||
for i = 1, len do
|
||||
sum = sum + (v1[i] - v2[i]) ^ 2
|
||||
end
|
||||
return math.sqrt(sum)
|
||||
end,
|
||||
copy = function(v)
|
||||
--vector_check(v, 2, 'copy')
|
||||
return vector_new(v)
|
||||
end,
|
||||
}
|
||||
vector_new = function(vi)
|
||||
if vi then
|
||||
if type(vi)=='string' then
|
||||
local vi2 = {}
|
||||
for val in vi:gmatch('[0-9%.%-e]+') do
|
||||
table.insert(vi2, tonumber(val))
|
||||
end
|
||||
vi = vi2
|
||||
elseif type(vi)~='table' then
|
||||
error('vector: argument #1: expected input table, got '..type(vi), 2)
|
||||
end
|
||||
local v = {}
|
||||
if #vi>0 then
|
||||
for i = 1, #vi do v[i] = vi[i] end
|
||||
else
|
||||
for n, i in pairs(vector_indices) do v[i] = vi[n] end
|
||||
if #v==0 then
|
||||
error('vector: argument #1: table contains no values', 2)
|
||||
end
|
||||
end
|
||||
setmetatable(v, vector_meta)
|
||||
return v
|
||||
else
|
||||
error('vector: argument #1: expected input table, got nil', 2)
|
||||
end
|
||||
if vi then
|
||||
if type(vi) == 'string' then
|
||||
local vi2 = {}
|
||||
for val in vi:gmatch('[0-9%.%-e]+') do
|
||||
table.insert(vi2, tonumber(val))
|
||||
end
|
||||
vi = vi2
|
||||
elseif type(vi) ~= 'table' then
|
||||
error('vector: argument #1: expected input table, got ' .. type(vi), 2)
|
||||
end
|
||||
local v = {}
|
||||
if #vi > 0 then
|
||||
for i = 1, #vi do v[i] = vi[i] end
|
||||
else
|
||||
for n, i in pairs(vector_indices) do v[i] = vi[n] end
|
||||
if #v == 0 then
|
||||
error('vector: argument #1: table contains no values', 2)
|
||||
end
|
||||
end
|
||||
setmetatable(v, vector_meta)
|
||||
return v
|
||||
else
|
||||
error('vector: argument #1: expected input table, got nil', 2)
|
||||
end
|
||||
end
|
||||
|
||||
vector = vector_new
|
||||
|
||||
Reference in New Issue
Block a user