BlitzMax/Modules/Axe/Lua
Lua脚本通常在VM(虚拟机)中运行。因此,我们首先启动一个VM,然后加载基本的Lua库
Local LuaState:byte ptr = luaL_newstate() luaL_openlibs(LuaState)
luaL_newstate() 返回的字节指针在每次Lua函数调用时都需要。现在你已经完成了初始化,可以开始运行脚本了。
之后关闭Lua VM可以通过一个函数完成
lua_close(LuaState)
Lua脚本可以直接从Blitzmax字符串中执行。
Local Script:String = "print(~qHello World!~q)" luaL_loadString(LuaState,Script)
这段代码加载并编译了脚本。如果出现问题,luaL_loadString() 会返回一个 <> 0 的值。
lua_getfield(LuaState, LUA_GLOBALSINDEX, "debug")' get global "debug" lua_getfield(LuaState, -1, "traceback") ' get "debug.traceback" lua_remove (LuaState, -2) ' remove "debug" table from stack
这些命令现在不重要,它们只是为了获得正确的错误信息。
lua_pcall(LuaState,1,-1,-1)' use "debug.traceback" as err.hdlr
这行代码实际上执行了脚本。同样,如果它的返回值是 <> 0,则发生了错误。如果一切都正常,程序将按照预期显示一个“Hello World!”。
你可能已经注意到,仅仅能够运行脚本而不能与BlitzMax交互并没有什么用。因此,下一步就是学习如何从Lua脚本调用BlitzMax函数。不幸的是,我们不能直接使用任意函数,因为函数必须遵循特定的布局
Function BMXName:int (LuaState:Byte Ptr) ... ' handling of parameters passed from Lua (if required) ... ' actual function body ... ' passing results back to Lua (if required) return 0 ' number of values returned to Lua function End Function
显然,在Lua脚本中使用函数提交的参数不会直接传输到BlitzMax函数。我们必须手动处理它们,但不要急于求成。首先,我们需要将函数注册到Lua
lua_register(LuaState, "luaname", BMXName)
现在可以在Lua(全局)中以luaname() 的形式调用BMXName()。你可能选择将函数命名与BlitzMax中相同,但你没有必要这样做。
假设我们尝试从Lua调用
luaname(810, "Hallo!")
使用上面的示例函数。Lua没有抱怨额外的参数,但我们也无法从函数内部访问它们。它们到哪里去了?Lua将它们放置在参数堆栈上。每个参数都被分配了一个索引,可以通过该索引识别。索引按顺序编号,从1开始。因此,810 可以在索引1处找到,“Hallo!”可以在索引2处找到。现在我们只需要知道从参数堆栈读取值的相应命令,我们就完成了
Function BMXName:Int (LuaState:Byte Ptr) Local int_value:Int = luaL_checkinteger(LuaState, 1) Local str_value:String = luaL_checkstring(LuaState, 2) Print int_value Print str_value Return 0 ' number of values returned to Lua function End Function
返回一个或多个值到Lua脚本的操作类似,但你不必指定索引,因为值会自动追加到堆栈。以下是一个示例
Function BMXName:Int (LuaState:Byte Ptr) lua_pushnumber(LuaState, 810) lua_pushstring(LuaState, "Hallo!") Return 2 ' number of values returned to Lua function End Function
在大多数情况下,你只会返回一个值或根本不返回值,但如你所见,也可以返回更多值。
我们知道如何执行完整的Lua脚本,但如果我们只需要一个函数呢?在这种情况下,你首先必须将要调用的函数放在堆栈上,然后是参数。以下是一个示例。Lua脚本
function luafunc(para, str) print(para, str) end
BlitzMax代码
lua_getfield(LuaState, LUA_GLOBALSINDEX, "luafunc") 'Puts the function onto the stack lua_pushinteger(LuaState, 810) 'First Argument lua_pushstring(LuaState, "Hallo!") 'Second Argument lua_call(LuaState, 2, 0) 'Call the function with 2 arguments and no result
如果有返回值,它们会在函数执行后被放置到堆栈上。
lua_pushstring(LuaState, "Hallo!") lua_setglobal (LuaState, "luaglobal")
第一个命令将“Hallo!”写入堆栈,第二个命令将它放入全局luaglobal。
lua_getglobal(LuaState, "luaglobal") Local str:String = lua_tostring(LuaState, -1)
第一个命令将值放入堆栈,第二个命令将它放入BlitzMax变量。
如果你想保存当前Lua VM的状态,你需要找到一种方法来获取所有全局变量。一种方法是使用lua_next函数
lua_pushnil(LuaState) ' first key While (lua_next(LuaState, LUA_GLOBALSINDEX) <> 0) ' iterate through all values of the global environment table ' uses 'key' (at index -2) and 'value' (at index -1) Print(lua_typename(LuaState,lua_type(LuaState , - 1))+" - "+lua_tostring(LuaState,-2)+"-"+lua_tostring(LuaState,-1)) ' removes 'value'; keeps 'key' for next iteration lua_pop(LuaState, 1); Wend
请注意,这种方法不仅返回全局变量,还返回函数、表等,你需要使用lua_type命令来进行分类。