LUA Implementation Limitations & Notes: Difference between revisions

From SkyCorp Global
Jump to navigation Jump to search
No edit summary
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
Underworld's LUA VM is a modified version of the 2009 [https://code.google.com/archive/p/lufacode/ lufacode] project. It implements a small subset of the LUA 5.1 specification.
Our LUA VM is based on [https://www.moonsharp.org/ MoonSharp], which implements (more or less) the [https://www.lua.org/manual/5.2/manual.html LUA 5.2] specification.
 
== Features ==
The following interpreter features are enabled:
 
* Global Consts ("_G", "_VERSION" and "_MOONSHARP")
*[[Global LUA Functions|Table Iterators]] ("next", "ipairs" and "pairs")
* Strings
* [[Table|Tables]]
* Basic ("assert", "collectgarbage", "error", "print", "select", "type", "tonumber" and "tostring")
* Math
* Bit32
 
== Caveats ==
Some caveats to be aware of when writing LUA code for it:


There's a lot of caveats to be aware of when writing LUA code for it:
* This page describing known [https://www.moonsharp.org/moonluadifferences.html differences in MoonSharp] may be helpful, in particular [https://www.moonsharp.org/MoonSharpStdLib.pdf differences in std lib].
* A LUA global is registered under the name 'this' to point to the LUA object that is executing the code.
*A LUA global is registered under the name 'this' to point to the LUA object that is executing the code.
** See [[Sample: GPS|GPS]] for a sample.
** See [[Sample: GPS|GPS]] for a sample.
** However, as this is just a global variable and not an actual language keyword, if your code creates classes, 'this' will still point to the entity.
** However, as this is just a global variable and not an actual language keyword, if your code creates classes, 'this' will still point to the entity.
* Equality operator on entities, maps, locations, and other Underworld classes should be generally avoided currently
*Equality operator on entities, maps, locations, and other Underworld classes should be generally avoided currently
** This is because AS3 will return a new LUA table for each requested class.  In future, these will be cached which ''should'' allow for accurate equality comparison.  In the meanwhile, you can check locations equality by comparing if they both have the same RoomID and map.getName.  Entity equality is trickier since many entities may share the same name.
** This is because AS3 will return a new LUA table for each requested class.  In future, these will be cached which ''should'' allow for accurate equality comparison.  In the meanwhile, you can check locations equality by comparing if they both have the same RoomID and map.getName.  Entity equality is trickier since many entities may share the same name.
*If you encounter unexpected bugs, post on discord with a link to some sample code to reproduce the bug.
*If you run into a wall due to functions not being exposed to LUA, please leave feedback on what you would like to build with the mod API but can't due to current limitations!  This helps inform future revisions of the mod API.
== Old LUFA (AS3 LUA) version notes (no longer relevant) ==
Old notes (largely outdated?  Based on the old AS3 version)
{| class="wikitable mw-collapsible mw-collapsed"
|+Outdated information hidden for now
|
Underworld's LUA VM is a modified version of the 2009 [https://code.google.com/archive/p/lufacode/ lufacode] project.  It implements a small subset of the LUA 5.1 specification.
There's a lot of caveats to be aware of when writing LUA code for it:
* Most LUA library functions are not implemented
* Most LUA library functions are not implemented
** This includes the pairs function.  Foreach is available, however.  I've also implemented a simple table.keys function as a workaround (see the clone [[LUA Utility Functions|utility function]] that uses it)
** This includes the pairs function.  Foreach is available, however.  I've also implemented a simple table.keys function as a workaround (see the clone [[LUA Utility Functions|utility function]] that uses it)
* Sometimes LUFA returns an array with the first return parameter correct, but additional entries of garbage data.  An example of this is the [[Weight Pendant]].
**This code did not work:<syntaxhighlight lang="lua">
      io.write(GameText.parseText("You try to take off the pendant with " ..
        "your [[HANDS DESCRIPTION]], but it won't budge... it's " ..
        "cursed!\n\n"));
</syntaxhighlight>It caused the correct line to be output, followed by each of the raw lines.
** Changing this to the MainScreen caused only the first parameter to print, thus working correctly.<syntaxhighlight lang="lua">
      MainScreen.addGameText(GameText.parseText("You try to take off the " ..
        "pendant with your [[HANDS DESCRIPTION]], but it won't budge... " ..
        "it's cursed!\n\n"));
</syntaxhighlight>Possibly something going on with the lua stack?  If anyone wants to dive into LUFA and figure out what's going on, a patch is much appreciated!
* Sometimes LUFA doesn't pass values correctly when it should first evaluate a function (could it be related to the above issue?)
** Example -- assume that WYVERN_IDLE_WITH_MATE is a table, and arrayLength() is a local helper function
** This code did not work:<syntaxhighlight lang="lua">
local randomIndex = math.random(1,arrayLength(WYVERN_IDLE_WITH_MATE));
</syntaxhighlight>It passed to math.random three variables, including the WYVERN_IDLE_WITH_MATE table
** This code worked okay:<syntaxhighlight lang="lua">
local maxIdles = arrayLength(WYVERN_IDLE_WITH_MATE);
local randomIndex = math.random(1,maxIdles);
</syntaxhighlight>Passes only two values to math.random correctly.
*Inheritance, and most stuff with __index doesn't ''seem'' to work.  However, someone with more LUA experience should verify this.
*Inheritance, and most stuff with __index doesn't ''seem'' to work.  However, someone with more LUA experience should verify this.
*Each entity currently runs in its own VM, and not in an OOP fashion.
*Each entity currently runs in its own VM and not actually as an object oriented setup.
**It's not currently possible to make calls between custom functions on different objects.  May be able to come up with a hacky message-passing solution for this in future if it's desired. 
**<s>It's not currently possible to make calls between custom functions on different objects.</s>  Now possible as of r35!  See [[Sample: Radio|Radio sample]].  
**A better solution would be an object oriented programming design.  Unfortunately, LUFA doesn't currently support AS3 calling into a function on an object, nor does it support Inheritance, which makes it hard to have multiple objects running in the same VM.  This could potentially be mitigated by having function names of the format AuthorObjectFunction(), all running in the same VM.  However, in this first proof of concept of LUA modding, I'm going to defer in the hopes that someone wants to update LUFA and make it more OOP supporting so as to allow a future iteration of modding in the 'right' OOP way.  With each entity structured with OOP, all entities could run in the same VM and call each other's methods directly.
**A better solution would be an object oriented programming design.  Unfortunately, LUFA doesn't currently support AS3 calling into a function on an object, nor does it support Inheritance, which makes it hard to have multiple objects running in the same VM.  So separate VMs and a bunch of internal facades kind of simulate object oriented patterns as of r35.
*The LUA integration/API may change in future.  For this reason, it is highly suggested to post your LUA source code when you post entity mods.  That way, someone might help update them if you're no longer around / don't want to.  Also, then people can learn from each other and make better mods!
*The LUA integration/API may change in future.  For this reason, it is highly suggested to post your LUA source code when you post entity mods.  That way, someone might help update them if you're no longer around / don't want to.  Also, then people can learn from each other and make better mods!
*If anyone wants to improve LUA language support, check out the lufacode source link above.  After you've had a chance to download and play with it a bit, I can post my modified version as a starting point.
*If anyone wants to improve LUA language support, check out the lufacode source link above.  After you've had a chance to download and play with it a bit, I can post my modified version as a starting point.
**LUA wishlist:
**LUA wishlist:
***Fix weird multiple return issue (see above about Weight Pendant)
***Inheritance support
***Inheritance support
***Ability to call functions on objects from AS3 so as to support an OOP design (see above rant)
***Ability to call functions on objects from AS3 so as to support an OOP design (see above rant) (less of an issue as of r35, but would still be nice)
***In-game LUA compiler so as to simplify the luac -> base64 -> edit json -> execute loop
***<nowiki>**In-game LUA compiler & editor so as to simplify the luac -> base64 -> edit json -> execute loop</nowiki>
*If you encounter unexpected bugs, post on discord with a link to some sample code to reproduce the bug.
*
*If you run into a wall due to functions not being exposed to LUA, please leave feedback on what you would like to build with the mod API but can't due to current limitations!  This helps inform future revisions of the mod API.
|}

Latest revision as of 05:49, 13 July 2023

Our LUA VM is based on MoonSharp, which implements (more or less) the LUA 5.2 specification.

Features

The following interpreter features are enabled:

  • Global Consts ("_G", "_VERSION" and "_MOONSHARP")
  • Table Iterators ("next", "ipairs" and "pairs")
  • Strings
  • Tables
  • Basic ("assert", "collectgarbage", "error", "print", "select", "type", "tonumber" and "tostring")
  • Math
  • Bit32

Caveats

Some caveats to be aware of when writing LUA code for it:

  • This page describing known differences in MoonSharp may be helpful, in particular differences in std lib.
  • A LUA global is registered under the name 'this' to point to the LUA object that is executing the code.
    • See GPS for a sample.
    • However, as this is just a global variable and not an actual language keyword, if your code creates classes, 'this' will still point to the entity.
  • Equality operator on entities, maps, locations, and other Underworld classes should be generally avoided currently
    • This is because AS3 will return a new LUA table for each requested class. In future, these will be cached which should allow for accurate equality comparison. In the meanwhile, you can check locations equality by comparing if they both have the same RoomID and map.getName. Entity equality is trickier since many entities may share the same name.
  • If you encounter unexpected bugs, post on discord with a link to some sample code to reproduce the bug.
  • If you run into a wall due to functions not being exposed to LUA, please leave feedback on what you would like to build with the mod API but can't due to current limitations! This helps inform future revisions of the mod API.

Old LUFA (AS3 LUA) version notes (no longer relevant)

Old notes (largely outdated? Based on the old AS3 version)

Outdated information hidden for now

Underworld's LUA VM is a modified version of the 2009 lufacode project. It implements a small subset of the LUA 5.1 specification.

There's a lot of caveats to be aware of when writing LUA code for it:

  • Most LUA library functions are not implemented
    • This includes the pairs function. Foreach is available, however. I've also implemented a simple table.keys function as a workaround (see the clone utility function that uses it)
  • Sometimes LUFA returns an array with the first return parameter correct, but additional entries of garbage data. An example of this is the Weight Pendant.
    • This code did not work:
            io.write(GameText.parseText("You try to take off the pendant with " ..
               "your [[HANDS DESCRIPTION]], but it won't budge... it's " ..
               "cursed!\n\n"));
      
      It caused the correct line to be output, followed by each of the raw lines.
    • Changing this to the MainScreen caused only the first parameter to print, thus working correctly.
            MainScreen.addGameText(GameText.parseText("You try to take off the " ..
               "pendant with your [[HANDS DESCRIPTION]], but it won't budge... " ..
               "it's cursed!\n\n"));
      
      Possibly something going on with the lua stack? If anyone wants to dive into LUFA and figure out what's going on, a patch is much appreciated!
  • Sometimes LUFA doesn't pass values correctly when it should first evaluate a function (could it be related to the above issue?)
    • Example -- assume that WYVERN_IDLE_WITH_MATE is a table, and arrayLength() is a local helper function
    • This code did not work:
      local randomIndex = math.random(1,arrayLength(WYVERN_IDLE_WITH_MATE));
      
      It passed to math.random three variables, including the WYVERN_IDLE_WITH_MATE table
    • This code worked okay:
      local maxIdles = arrayLength(WYVERN_IDLE_WITH_MATE);
      local randomIndex = math.random(1,maxIdles);
      
      Passes only two values to math.random correctly.
  • Inheritance, and most stuff with __index doesn't seem to work. However, someone with more LUA experience should verify this.
  • Each entity currently runs in its own VM and not actually as an object oriented setup.
    • It's not currently possible to make calls between custom functions on different objects.  Now possible as of r35! See Radio sample.
    • A better solution would be an object oriented programming design.  Unfortunately, LUFA doesn't currently support AS3 calling into a function on an object, nor does it support Inheritance, which makes it hard to have multiple objects running in the same VM.  So separate VMs and a bunch of internal facades kind of simulate object oriented patterns as of r35.
  • The LUA integration/API may change in future. For this reason, it is highly suggested to post your LUA source code when you post entity mods. That way, someone might help update them if you're no longer around / don't want to. Also, then people can learn from each other and make better mods!
  • If anyone wants to improve LUA language support, check out the lufacode source link above. After you've had a chance to download and play with it a bit, I can post my modified version as a starting point.
    • LUA wishlist:
      • Fix weird multiple return issue (see above about Weight Pendant)
      • Inheritance support
      • Ability to call functions on objects from AS3 so as to support an OOP design (see above rant) (less of an issue as of r35, but would still be nice)
      • **In-game LUA compiler & editor so as to simplify the luac -> base64 -> edit json -> execute loop