Lua Module Tweaks
BlitzMax Forums/BlitzMax Module Tweaks/Lua Module Tweaks
| ||
Some Lua module tweaks to make it easier to work with (less calling "String.ToCString" and "String.FromCString"). Refer to the History if you want to read the exact explanation. Strict Rem bbdoc: LUA Core End Rem Module Pub.lua ModuleInfo "Version: 1.13" ModuleInfo "Author: Tecgraf, PUC-Rio" ModuleInfo "License: MIT License" ModuleInfo "Modserver: BRL" ModuleInfo "Credit: Adapted for BlitzMax by Thomas Mayer & Noel Cower" ModuleInfo "History: Added luaopen_debug and ldblib.c" ModuleInfo "History: Replaced Byte Ptr with $z (CString) where a C string is expected" ModuleInfo "History: Release 1.13" ModuleInfo "History: Release 1.12" ModuleInfo "History: Removed lua.h import" Import "lstate.c" Import "llex.c" Import "ltm.c" Import "lstring.c" Import "ltable.c" Import "lfunc.c" Import "ldo.c" Import "lgc.c" Import "lzio.c" Import "lobject.c" Import "lparser.c" Import "lvm.c" Import "lundump.c" Import "lmem.c" Import "lcode.c" Import "ldebug.c" Import "lopcodes.c" Import "lapi.c" Import "ldump.c" Import "lbaselib.c" Import "lauxlib.c" Import "liolib.c" Import "lmathlib.c" Import "lstrlib.c" Import "ltablib.c" Import "ldblib.c" Const LUA_TNONE = -1 Const LUA_TNIL = 0 Const LUA_TBOOLEAN = 1 Const LUA_TLIGHTUSERDATA = 2 Const LUA_TNUMBER = 3 Const LUA_TSTRING = 4 Const LUA_TTABLE = 5 Const LUA_TFUNCTION = 6 Const LUA_TUSERDATA = 7 Const LUA_TTHREAD = 8 Const LUA_REGISTRYINDEX = -10000 Const LUA_GLOBALSINDEX = -10001 Extern ''' INIT FUNCTIONS ''' Function lua_open:Byte Ptr() Function lua_close(lua_state:Byte Ptr) Function luaopen_base(lua_state:Byte Ptr) Function luaopen_table(lua_state:Byte Ptr) Function luaopen_io(lua_state:Byte Ptr) Function luaopen_string(lua_state:Byte Ptr) Function luaopen_math(lua_state:Byte Ptr) Function luaopen_debug(lua_state:Byte Ptr) ''' END INIT FUNCTIONS ''' ''' LOADING FUNCTIONS ''' Function luaL_loadbuffer(lua_state:Byte Ptr, buffer:Byte Ptr, buffersize, name$z) ''' END LOADING FUNCTIONS ''' ''' EXECUTION FUNCTIONS ''' Function lua_dofile(lua_state:Byte Ptr, filename$z) Function lua_pcall(lua_state:Byte Ptr, nargs:Int, nresults:Int, errfunc:Int) ''' END EXECUTION FUNCTIONS ''' ''' CONVERT FUNCTIONS ''' Function lua_tostring$z(lua_state:Byte Ptr, index:Int) Function lua_toboolean:Int(lua_state:Byte Ptr, index:Int) Function lua_tonumber:Double(lua_state:Byte Ptr, index:Int) Function lua_strlen:Int(lua_state:Byte Ptr, index:Int) Function lua_tothread:Byte Ptr(ls:Byte Ptr,index:Int) Function lua_touserdata:Byte Ptr(ls:Byte Ptr,index:Int) ''' END CONVERT FUNCTIONS ''' ''' TYPE INFO FUNCTIONS ''' Function lua_typename:Byte Ptr(lua_state:Byte Ptr, typenumber:Int) Function lua_type:Int(lua_state:Byte Ptr, index:Int) Function lua_isnumber:Int(lua_state:Byte Ptr, index:Int) Function lua_isstring:Int(lua_state:Byte Ptr, index:Int) Function lua_isuserdata:Int(ls:Byte Ptr, index:Int) Function lua_iscfunction:Int(ls:Byte Ptr, index:Int) ''' END TYPE INFO FUNCTIONS ''' ''' STACK AND DATA FUNCTIONS ''' Function lua_next(lua_state:Byte Ptr, idx:Int) Function lua_error(lua_state:Byte Ptr) Function lua_call(lua_state:Byte Ptr,nargs:Int, nres:Int) Function lua_newtable(lua_state:Byte Ptr) Function lua_getfield(name:Byte Ptr) Function lua_gettable(lua_state:Byte Ptr, tableIndex:Int) Function lua_settable(lua_state:Byte Ptr, tableIndex:Int) Function lua_settop(lua_state:Byte Ptr, index:Int) Function lua_gettop:Int(lua_state:Byte Ptr) Function lua_rawset(lua_state:Byte Ptr, idx:Int) Function lua_rawget(lua_state:Byte Ptr, idx:Int) Function lua_pushvalue(lua_state:Byte Ptr, value:Int) Function lua_remove(lua_state:Byte Ptr, value:Int) Function lua_insert(lua_state:Byte Ptr, value:Int) Function lua_replace(lua_state:Byte Ptr, value:Int) Function lua_pushcclosure(lua_state:Byte Ptr, func:Int(ls:Byte Ptr), val:Int) Function lua_pushnil(lua_state:Byte Ptr) Function lua_pushnumber(lua_state:Byte Ptr, value:Double) Function lua_pushboolean(lua_state:Byte Ptr, value:Int) Function lua_pushlstring(lua_state:Byte Ptr, value$z, size:Int) Function lua_pushstring(lua_state:Byte Ptr, value$z) Function lua_pushlightuserdata(lua_state:Byte Ptr, p:Byte Ptr) Function lua_checkstack:Int(lua_state:Byte Ptr, size:Int) Function luaL_checklstring:Byte Ptr(lua_state:Byte Ptr, argNum:Int, size:Int) Function luaL_checknumber:Double(lua_state:Byte Ptr, argNum:Int) ''' END STACK AND DATA FUNCTIONS ''' End Extern ' Re-written from LUA.H, Macro was not expanding correctly Function lua_pop(lua_state:Byte Ptr, index:Int) lua_settop(lua_state, -(index)-1) End Function Function lua_isboolean:Int(lua_state:Byte Ptr, index:Int) Return (lua_type(lua_state, index) = LUA_TBOOLEAN) End Function Function lua_getglobal(lua_state:Byte Ptr, name$z) lua_pushstring(lua_state, name) lua_gettable(lua_state, LUA_GLOBALSINDEX) End Function Function lua_pushcfunction(lua_state:Byte Ptr, func:Int(ls:Byte Ptr)) lua_pushcclosure(lua_state, func, 0) End Function Function lua_setglobal(lua_state:Byte Ptr, name$z) lua_pushstring(lua_state, name) lua_insert(lua_state, -2) lua_settable(lua_state, LUA_GLOBALSINDEX) End Function Function lua_register(lua_state:Byte Ptr, name$z, func:Int(ls:Byte Ptr)) lua_pushstring(lua_state, name) lua_pushcfunction(lua_state, func) lua_settable(lua_state, LUA_GLOBALSINDEX) End Function Function luaL_checkstring:Byte Ptr(lua_state:Byte Ptr, index:Int) Return luaL_checklstring(lua_state, index, Null) End Function Function luaL_checkint:Int(lua_state:Byte Ptr, argNum:Int) Return luaL_checknumber(lua_state, argNum) End Function Function lua_istable:Int(lua_state:Byte Ptr, index:Int) Return (lua_type(lua_state,index) = LUA_TTABLE) End Function |
| ||
Could you add access to luaopen_debug? This would be very helpful for being able to write error handling functions in Lua, able to pull out callstack information. |
| ||
Done, plus a minor tweak to luaL_loadbuffer. |
| ||
What's with the forum times? |
| ||
They freak around month end. I think that on the first day of each month, any posts onthe last day of the previous month think they were made that day. There's a +1 missing somehwere... |
| ||
Are the changes not reflected in the current sync mods? |
| ||
I have a tiny question about using LUA. I'm using it to do missions for my game. Say I have a mission type, LUAMission which runs a LUA file and uses the file to perform update(), etc, like this:LUA: function update() print("I'm updating...") end updateVar = 1 Do I need to run each mission using a seperate ScriptEngine? As I was wondering whether the globals in each mission would be added to the scriptEngine, if I was only using one script engine I'd be overwriting globals. Anyone know if it's the way you're supposed to do it? |
| ||
I think I'll make my problem clearer as I really need to solve it. I have a mission (courier mission) based on a LUA script. In bmx I've got:Global activeMissions:TList=CreateList() Global scriptEngine1:ScriptEngine=New ScriptEngine ScriptEngine1.AddFunction(LUA_getRandomSystem, "getRandomSystem") ' returns a system's name ' this function gets a random System from the game and passes the name back to then LUA script Function LUA_getRandomSystem(ls:Byte Ptr) Local s:system=getRandomSystem() ScriptEngine1.ReturnStringToLua(ls,Lower(s.name)) Return 1 End Function Type LUAMission Field description$ ' comes from LUA using functions added to the global ScriptEngine Function createMission:LUAMission(file$) Local i:LUAMission=New LUAMission ScriptEngine1.RunScriptFile(file) i.createPrototype() ScriptEngine1.BeginLUAFunctionCall() ScriptEngine1.CallFunction("getDescription", True) i.description = ScriptEngine1.GetResultString() ' get the description generated from LUA using the above added function End Function Method CreatePrototype() ' runs a function in the LUA file to get a description of the mission and pass it back. ScriptEngine1.BeginLUAFunctionCall() ScriptEngine1.CallFunction("prototype", True) Return Int(ScriptEngine1.GetResultNumber()) ' worked ok? End Method Method update() ScriptEngine1.BeginLUAFunctionCall() ScriptEngine1.CallFunction("update", True) Local result=Int(ScriptEngine1.GetResultNumber()) If result=1 ' mission is complete. and a success! give the player some money ElseIf result=-1' failure ' what a failure EndIf ListRemove(activeMissions,Self) End Method End Type Function updateMissions() For Local i:LUAMission=EachIn activeMissions i.update() Next End Function ' ------------------------------------------ SCRIPT FROM LUA randomSystem = getRandomSystem() ' calls attached function Print("LUA -> Main run OK.") Print("LUA -> Random System: "+randomSystem) ' this works fine. Function getDescription() Return "Get my package to "..randomSystem End Function updateMission() ' this is called to update mission objectives... ' specifics not important, but suffice to say this function check to see whether the player is in the ' system and docked at the right station. ' if it's successful it'll return 1 ' otherwise it'll return 0 ' if it's completely unsuccessful it'll return -1 ' the problem is when I've taken more than one mission the 'randomSystem' ' variable gets overridden by the most recent run of the script. End End What I'm really looking for is a way to make variables defined in this script local to this script. So if I run "courier.lua" and it generates a system name and puts it in its own randomSystem variable, if I run it again it won't override. Hmmm... I must have to run it in a seperate context. Like another scriptEngine. But does that mean I have to add all the functions I'm using to that scriptEngine? And if so, how do I associate the LUA linked functions like this: Function LUA_getRandomSystem(ls:Byte Ptr) Local s:system=getRandomSystem() If s <> Null ScriptEngine1.ReturnStringToLua(ls,Lower(s.name)) Else ScriptEngine1.ReturnStringToLua(ls,"BMX<->LUA ERROR") EndIf Return 1 End Function to my game. Can I specify another parameter to that function that passes the scriptEngine I'm using? Won't it mess with something? Can anyone gimme a hand? Matt |
| ||
Ok, I seem to understand it a bit better now. The scriptEngine interface was hiding a bit too much plus I finally noticed the ls:byte Ptr was the lua state the script engine was holding. I made my mission type use the script engine but passed the lua state to the attached functions. I think it'll work but bmx stops at: lua_pushstring(ls, file.ToCString()) with an "enable to convert from 'byte ptr' to 'CString' Anyone know what's up with that? Thanks to http://www.blitzbasic.com/Community/posts.php?topic=48411 and Noel's LUA tutorial wiki sample code. |
| ||
OK, never mind. I just reinstalled the latest update. Something must have overwritten something cost toCString didn't get recognised at all. Works now. |
| ||
Rimmsy: I don't use the ScriptEngine class and I would honestly advise against it. It would be far wiser to write a specialized system so that you don't have to work around stuff in the class. Plus, my brain isn't working right now. null_term: No. |
| ||
Thanks Noel. I haven't got time to do what you suggest although I'd really like to. Seems like scriptEngine works against you slightly by hiding some important stuff. Once you get a look at the core it's a lot more straight forward. I'll have a go at doing as you suggest and adding to the tutorial section as it's been a learning process... which you've helped. Thanks. |
| ||
Bump. These changes aren't in the update, so anyone who was using them you'll have to apply them again. BRL: Keep an eye on the module tweaks forum, ok? |
| ||
They do. They implemented Tim's improved ImageFonts stuff. |
| ||
Bump. Still not added. |
| ||
I got some conflicts with luascript.bmx with the $z changes so have converted everything to use :byte ptr to avoid confusion, but now I'm thinking you probably wanted to convert everything to go to $z, if so, can you post your latest luascript.bmx file also. |
| ||
Keep in mind that I don't use the luascript module, but rather my own, so I make no guarantees to whether or not this still works (although I really don't see why it wouldn't).Strict Rem bbdoc: LUA Script Engine End Rem Module Pub.luascript ModuleInfo "Version: 1.12" ModuleInfo "Author: Thomas Mayer" ModuleInfo "License: Public Domain" ModuleInfo "Modserver: BRL" Import Pub.lua Import brl.linkedlist Import brl.basic Const SE_TYPE_NUMBER = 0 Const SE_TYPE_STRING = 1 Const SE_TYPE_BOOLEAN = 2 Const SE_TYPE_TABLE = 3 Type SE_Parameter Field m_paramType Field m_valueNumber:Double Field m_valueString:String Field m_valueBoolean:Int ' Function CreateString:SE_Parameter(value:String) ' Local returnParam:SE_Parameter = New SE_Parameter ' returnParam.m_paramType = SE_TYPE_STRING ' returnParam.m_valueString = value ' Return returnParam ' End Function ' Function CreateBoolean:SE_Parameter(value:Int) ' Local returnParam:SE_Parameter = New SE_Parameter ' returnParam.m_paramType = SE_TYPE_BOOLEAN ' returnParam.m_valueBoolean = value ' Return returnParam ' End Function ' Function CreateNumber:SE_Parameter(value:Double) ' Local returnParam:SE_Parameter = New SE_Parameter ' returnParam.m_paramType = SE_TYPE_NUMBER ' returnParam.m_valueNumber = value ' Return returnParam ' End Function End Type Rem bbdoc: Lua script engine type End Rem Type ScriptEngine Field m_started:Int Field m_source:String Field m_lastErrorString:String Field m_lastErrorNumber:Int Field m_lua_state:Byte Ptr Field m_paramList:TList = CreateList() Field m_resultString:String = "" Field m_resultNumber:Double = 0 Field m_resultBoolean:Int = 0 Field m_resultType:Int = -1 ' Default constructor Method New() Reset() End Method Rem bbdoc: Resets the engine back to a start state End Rem Method Reset() If (m_lua_state) Then lua_close(m_lua_state) m_lua_state = lua_open() If (m_lua_state) Then luaopen_base(m_lua_state) luaopen_table(m_lua_state) luaopen_io(m_lua_state) luaopen_string(m_lua_state) luaopen_math(m_lua_state) m_started = True Else m_started = False End If End Method Rem bbdoc: Returns a string back to LUA from a callback BMX function End Rem Method ReturnStringToLua(lua_state:Byte Ptr, value:String) If (m_started) Then lua_pushstring(lua_state, value) End If End Method Rem bbdoc: Returns a number back to LUA from a callback BMX function End Rem Method ReturnNumberToLua(lua_state:Byte Ptr, value:Double) If (m_started) Then lua_pushnumber(lua_state, value) End If End Method Rem bbdoc: Returns a boolean back to LUA from a callback BMX function End Rem Method ReturnBooleanToLua(lua_state:Byte Ptr, value:Int) If (m_started) Then lua_pushboolean(lua_state, value) End If End Method Rem bbdoc: Adds a Function into the LUA environment End Rem Method AddFunction(func:Int(ls:Byte Ptr), name:String) If (m_started) lua_register(m_lua_state, name, func) End If End Method Rem bbdoc: Performs initialization required for call a function in LUA End Rem Method BeginLUAFunctionCall() ClearList(m_paramList) m_ResultType = -1 m_ResultString = "" m_ResultNumber = 0 m_ResultBoolean = 0 End Method Rem bbdoc: Checks a string parameter and return its value End Rem Method CheckString:String(lua_state:Byte Ptr, index:Int) Return String.FromCString(luaL_checkstring(lua_state, index)) End Method Rem bbdoc: Checks a number parameter and return its value End Rem Method CheckNumber:Double(lua_state:Byte Ptr, index:Int) Return luaL_checknumber(lua_state, index) End Method ' Rem ' bbdoc: Checks a boolean parameter And Return its value ' End Rem Method CheckBoolean:Int(lua_state:Byte Ptr, index:Int) Return luaL_checkint(lua_state, index) End Method Rem bbdoc: Adds a string parameter to a LUA function call End Rem Method AddStringParameter(value:String) Local param:SE_Parameter = New SE_Parameter param.m_paramType = SE_TYPE_STRING param.m_valueString = value ListAddLast(m_paramList, param) End Method Rem bbdoc: Adds a number parameter to a LUA function call End Rem Method AddNumberParameter(value:Double) Local param:SE_Parameter = New SE_Parameter param.m_paramType = SE_TYPE_NUMBER param.m_valueNumber = value ListAddLast(m_paramList, param) End Method Rem bbdoc: Adds a boolean parameter to a LUA function call End Rem Method AddBooleanParameter(value:Int) Local param:SE_Parameter = New SE_Parameter param.m_paramType = SE_TYPE_BOOLEAN param.m_valueBoolean = value ListAddLast(m_paramList, param) End Method Rem bbdoc: Calls a function in LUA End Rem Method CallFunction:Int(functionName:String, wantResult:Int) Local param:SE_Parameter Local error:Int If (m_started) Then lua_getglobal(m_lua_state , functionName) For param = EachIn m_paramList Select param.m_paramType Case SE_TYPE_NUMBER lua_pushnumber(m_lua_state, param.m_valueNumber) Case SE_TYPE_STRING lua_pushstring(m_lua_state, param.m_valueString) Case SE_TYPE_BOOLEAN lua_pushboolean(m_lua_state, param.m_valueBoolean) End Select Next error = lua_pcall(m_lua_state, CountList(m_paramList), wantResult, 0) If ((Not error) And wantResult) Then If (lua_isnumber(m_lua_state, -1)) Then m_resultType = SE_TYPE_NUMBER m_resultNumber = lua_tonumber(m_lua_state, -1) lua_pop(m_lua_state, 1) Else If (lua_isboolean(m_lua_state, -1)) Then m_resultType = SE_TYPE_BOOLEAN m_resultBoolean = lua_toboolean(m_lua_state, -1) lua_pop(m_lua_state, 1) Else If (lua_isstring(m_lua_state, -1)) Then m_resultType = SE_TYPE_STRING m_resultString = lua_tostring(m_lua_state, -1) lua_pop(m_lua_state, 1) End If End If Else m_lastErrorString = "ScriptEngine: Engine is not started" m_lastErrorNumber = 0 Return False End If If (Not error) Then Return True ProcessError(error) Return False End Method Rem bbdoc: Tells the result type of a LUA function call End Rem Method GetResultType:Int() Return m_resultType End Method Rem bbdoc: Get the result of a LUA function call as a number End Rem Method GetResultNumber:Double() Return m_resultNumber End Method Rem bbdoc: Get the result of a LUA function call as a boolean End Rem Method GetResultBoolean:Int() Return m_resultBoolean End Method Rem bbdoc: Get the result of a LUA function call as a string End Rem Method GetResultString:String() Return m_resultString End Method Rem bbdoc: Internal End Rem Method ProcessError (errorCode:Int) m_LastErrorString = lua_tostring(m_lua_state, -1) m_LastErrorNumber = errorCode lua_pop(m_lua_state, -1) End Method Rem bbdoc: Set engine script text (performs syntax checks) End Rem Method SetScriptText:Int(scriptText:String, scriptName:String) Local error:Int m_Source = "" If (m_started) Then Local t:Byte Ptr=scriptText.ToCString() error = luaL_loadbuffer(m_lua_state, t, scriptText.length, scriptText) MemFree t Else m_lastErrorString = "ScriptEngine: Engine is not started" m_lastErrorNumber = 0 Return False End If If (Not error) Then m_Source = scriptText Return True End If ProcessError(error) Return False End Method Rem bbdoc: Runs a script file End Rem Method RunScriptFile:Int(scriptFile:String) Local error:Int If (m_started) Then error = lua_dofile(m_lua_state, scriptFile) Else m_lastErrorString = "ScriptEngine: Engine is not started" m_lastErrorNumber = 0 Return False End If If (Not error) Then Return True ProcessError(error) Return False End Method Rem bbdoc: Runs a script loaded with SetScriptText End Rem Method RunScript:Int() Local error:Int If (m_started) Then If (m_Source.length > 0) Then error = lua_pcall(m_lua_state, 0, 0, 0) Else m_lastErrorString = "ScriptEngine: No script text to execute" m_lastErrorNumber = 0 Return False End If Else m_lastErrorString = "ScriptEngine: Engine is not started" m_lastErrorNumber = 0 Return False End If If (Not error) Then Return True ProcessError(error) Return False End Method Rem bbdoc: Returns the last error string End Rem Method GetLastErrorString:String() Return m_LastErrorString End Method Rem bbdoc: Returns the last error number End Rem Method GetLastErrorNumber:Int() Return m_LastErrorNumber End Method Rem bbdoc: Destroys script engine state End Rem Method ShutDown() If (m_lua_state) Then lua_close(m_lua_state) m_started = False End Method Rem bbdoc: Returns whether or not the engine has started correctly End Rem Method Started:Int() Return m_started End Method End Type |