News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Using Lua

Started by Biterider, December 03, 2023, 04:36:56 AM

Previous topic - Next topic

Biterider

Hi
Some time ago an old friend (homer) mentioned to me that he wanted to use Lua as a scripting engine for his game framework. 
Recently I needed a similar solution in the short term and I decided to use Python. Nonetheless, I wanted to give Lua a try. 
I googled around a bit and was surprised to see how the community support has evolved in the meantime. I downloaded the c source code from https://www.lua.org/, compiled it, translated the header files and a few moments later I could call a very simple script from one of my assembler templates. Super cool  :cool:

I'm going to experiment a bit with some of the freely available modules/packages. A nice collection can be found here https://github.com/LewisJEllis/awesome-lua. As far as I can tell Lua is pretty easy to use and can be used for example as a backend scripting engine for an editor, game, server or anything else that needs configurable higher logic.

Biterider

fearless

Used some Lua in a project a while back:
https://github.com/mrfearless/EEexLoader/blob/master/EEexDLL/EEexLua.asm
It was using the internal lua that was compiled into a game executable, so that features and functionality could be expanded via additional lua usage.

Main things I recall in relation to using Lua with asm is:

- C style procedure declarations required. Except for your own leaf functions which can be declared as STDCALL.
- Usually VARARG argument as well, but not always. If you know that a function you create in asm will absolutely always use certain arguments then you can prototype with DWORD arguments.
- Lua state always required (from what i recall) when calling functions.
- Lua uses its own stack, so parameters etc have to be pushed onto the lua stack.
- Lua number values use float, so have to convert from float to int if receiving numeric values, and from int to float if pushing numeric values back onto lua stack - might be some lua functions to convert to and from int i think - i recall in the project above we had to hook ftol_sse function already in the game exe to use it to convert floats to long.

Here is some code I used whilst testing. It initializes a new lua state, opens the common libraries used in lua, calls a function to create a table. The table consists of a string column (name) and a number column (address). The string column is the name of a lua function found in the game engine and the number column is the address of that particular function. The function and table is available in lua for when using a lua script, the table created can be referenced and the name and address can be fetched.


EEex_AddressList        PROTO C :DWORD          ; lua_State

.DATA

luastate                DD 0

PatchLocation           DD 0
F_Lua_createtable       DD 0FF00AA00h
F_Lua_createtablex      DD 0
F_Lua_getglobal         DD 0
F_Lua_gettop            DD 0
F_Lua_pcallk            DD 0
F_Lua_pushcclosure      DD 0
F_Lua_pushlightuserdata DD 0
F_Lua_pushlstring       DD 0
F_Lua_pushnumber        DD 0
F_Lua_pushstring        DD 0
F_Lua_rawgeti           DD 0
F_Lua_rawlen            DD 0
F_Lua_setfield          DD 0
F_Lua_setglobal         DD 0
F_Lua_settable          DD 0
F_Lua_settop            DD 0
F_Lua_toboolean         DD 0
F_Lua_tolstring         DD 0
F_Lua_tonumberx         DD 0
F_Lua_touserdata        DD 0
F_Lua_type              DD 0
F_Lua_typename          DD 0
F_LuaL_loadstring       DD 0

.CODE
        ...
        Invoke luaL_newstate ; instead of lua_open
        mov luastate, eax       
       
        Invoke luaL_openlibs, luastate
       
        Invoke EEex_AddressList, luastate
        Invoke lua_gettable, luastate, 0
        Invoke lua_getfield, luastate, 0, CTEXT("_lua_createtable")
        Invoke lua_tointegerx, luastate, -5, 0
        PrintDec eax
        ...       

EEex_AddressList PROC C lua_State:DWORD
    LOCAL stk:DWORD
   
    PrintText 'EEex_AddressList'
    Invoke lua_createtable, lua_State, 0, 23
   
    Invoke lua_gettop, lua_State
    mov stk, eax
   
    Invoke lua_pushstring, lua_State, CTEXT("PatchLocation")
    Invoke lua_pushnumber, lua_State, PatchLocation   
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_createtable")
    Invoke lua_pushnumber, lua_State, F_Lua_createtable
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_getglobal")
    Invoke lua_pushnumber, lua_State, F_Lua_getglobal
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_gettop")
    Invoke lua_pushnumber, lua_State, F_Lua_gettop
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_pcallk")
    Invoke lua_pushnumber, lua_State, F_Lua_pcallk
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_pushcclosure")
    Invoke lua_pushnumber, lua_State, F_Lua_pushcclosure
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_pushlightuserdata")
    Invoke lua_pushnumber, lua_State, F_Lua_pushlightuserdata
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_pushlstring")
    Invoke lua_pushnumber, lua_State, F_Lua_pushlstring
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_pushnumber")
    Invoke lua_pushnumber, lua_State, F_Lua_pushnumber
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_pushstring")
    Invoke lua_pushnumber, lua_State, F_Lua_pushstring
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_rawgeti")
    Invoke lua_pushnumber, lua_State, F_Lua_rawgeti
    Invoke lua_settable, lua_State, stk

    Invoke lua_pushstring, lua_State, CTEXT("_lua_rawlen")
    Invoke lua_pushnumber, lua_State, F_Lua_rawlen
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_setfield")
    Invoke lua_pushnumber, lua_State, F_Lua_setfield
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_setglobal")
    Invoke lua_pushnumber, lua_State, F_Lua_setglobal
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_settable")
    Invoke lua_pushnumber, lua_State, F_Lua_settable
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_settop")
    Invoke lua_pushnumber, lua_State, F_Lua_settop
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_toboolean")
    Invoke lua_pushnumber, lua_State, F_Lua_toboolean
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_tolstring")
    Invoke lua_pushnumber, lua_State, F_Lua_tolstring
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_tonumberx")
    Invoke lua_pushnumber, lua_State, F_Lua_tonumberx
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_touserdata")
    Invoke lua_pushnumber, lua_State, F_Lua_touserdata
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_type")
    Invoke lua_pushnumber, lua_State, F_Lua_type
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_lua_typename")
    Invoke lua_pushnumber, lua_State, F_Lua_typename
    Invoke lua_settable, lua_State, stk
   
    Invoke lua_pushstring, lua_State, CTEXT("_luaL_loadstring")
    Invoke lua_pushnumber, lua_State, F_LuaL_loadstring
    Invoke lua_settable, lua_State, stk

    Invoke lua_setglobal, lua_State, CTEXT("LuaFunctions")

    PrintText 'EEex_AddressList finished'
    mov eax, 1
    ret
EEex_AddressList ENDP


And in the lua script it can reference those defined functions, the table, and its key value pairs of the name strings and number values and process something like the following:

EEex_GlobalAssemblyLabels = EEex_AddressList()

EEex_GlobalAssemblyLabels = {}
function EEex_DefineAssemblyLabel(label, value)
 EEex_GlobalAssemblyLabels[label] = value
end

function EEex_Label(label)
 local value = EEex_GlobalAssemblyLabels[label]
 if not value then
 EEex_Error("Label @"..label.." is not defined in the global scope!")
 end
 return EEex_GlobalAssemblyLabels[label]
end

for _, labelEntry in ipairs({
 {"CChitin::GetVersionString()_versionStringPush", 0x7902D7},
 {"_lua_getglobal", 0x4B5C10},
 {"_lua_gettop", 0x4B50A0},
 {"_lua_pcallk", 0x4B63F0},
 {"_lua_pushlightuserdata", 0x4B5BF0},
 {"_lua_pushnumber", 0x4B5960},
 {"_lua_pushstring", 0x4B5A40},
 {"_lua_rawgeti", 0x4B5D40},
 {"_lua_rawlen", 0x4B57B0},
 {"_lua_settop", 0x4B50C0},
 {"_lua_tolstring", 0x4B5710},
 {"_lua_tonumberx", 0x4B54D0},
 {"_lua_touserdata", 0x4B5840},
 {"_memset", 0x85B6A0},
 {"_p_malloc", 0x886FD0},
 {"_SDL_free", 0x7BF980},
 {"__ftol2_sse", 0x85C3C0},
 {"__imp__GetProcAddress", 0x8A0200},
 {"__imp__LoadLibraryA", 0x8A01D8},
 })
 do
 local labelName = labelEntry[1]
 local labelValue = labelEntry[2]
 EEex_DefineAssemblyLabel(labelName, labelValue)
 end

Thats just a rough example and the code and script above are just for reference to illustrate.


jj2007

C API
lua_Alloc
lua_CFunction
lua_Debug
lua_Hook
lua_Integer
lua_Number
lua_Reader
lua_State
lua_Writer
lua_atpanic
lua_call
lua_checkstack
lua_close
lua_concat
lua_cpcall
lua_createtable
lua_dump
lua_equal
lua_error
lua_gc
lua_getallocf
lua_getfenv
lua_getfield
lua_getglobal
lua_gethook
lua_gethookcount
lua_gethookmask
lua_getinfo
lua_getlocal
lua_getmetatable
lua_getstack
lua_gettable
lua_gettop
lua_getupvalue
lua_insert
lua_isboolean
lua_iscfunction
lua_isfunction
lua_islightuserdata
lua_isnil
lua_isnone
lua_isnoneornil
lua_isnumber
lua_isstring
lua_istable
lua_isthread
lua_isuserdata
lua_lessthan
lua_load
lua_newstate
lua_newtable
lua_newthread
lua_newuserdata
lua_next
lua_objlen
lua_pcall
lua_pop
lua_pushboolean
lua_pushcclosure
lua_pushcfunction
lua_pushfstring
lua_pushinteger
lua_pushlightuserdata
lua_pushliteral
lua_pushlstring
lua_pushnil
lua_pushnumber
lua_pushstring
lua_pushthread
lua_pushvalue
lua_pushvfstring
lua_rawequal
lua_rawget
lua_rawgeti
lua_rawset
lua_rawseti
lua_register
lua_remove
lua_replace
lua_resume
lua_setallocf
lua_setfenv
lua_setfield
lua_setglobal
lua_sethook
lua_setlocal
lua_setmetatable
lua_settable
lua_settop
lua_setupvalue
lua_status
lua_toboolean
lua_tocfunction
lua_tointeger
lua_tolstring
lua_tonumber
lua_topointer
lua_tostring
lua_tothread
lua_touserdata
lua_type
lua_typename
lua_upvalueindex
lua_xmove
lua_yield

Example:
Quotelua_atpanic

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
Sets a new panic function and returns the old one.

Biterider

Quote from: jj2007 on December 03, 2023, 12:33:26 PMC API
Code Select Expand
lua_Alloc
lua_CFunction...
The link from the previous post is unfortunately outdated. It leads to version 5.1 from ~Feb 2006. 
The documentation for the current lua version 5.4.6 can be found here
https://www.lua.org/manual/5.4/

Biterider