Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Lua and Unity

Discussion in 'Scripting' started by George Foot, Feb 22, 2012.

  1. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Edit - latest links for easy reference:

    ...

    I've recently had a need for user-level scripting, and have reimplemented an amalgamation of various open source Lua libraries which I used about a year ago. I'm wondering whether it's the kind of thing other people have a need for.

    It uses a library called LuaInterface, which allows a huge amount of bidirectional interoperation. For example, you can make a behaviour's FixedUpdate method call a Lua function, as well as read and write Lua variables. You can pass delegates to the Lua code, which can then call them directly, and the most significant thing LuaInterface provides is full access to .NET libraries - including UnityEngine, for example. So your Lua code can do pretty much anything your C# code can do, including creating GameObjects, moving them around, adding and removing components, and so on.

    The Lua interpreter is a full C# implementation (KopiLua), so it should work on all platforms, but it's not written for speed out of the box. There's a lot of room for optimization, but of course it will inevitably be slower than doing the same work in C#. Nevertheless, if you need dynamic scripting it might be a good solution.

    I'm interested in use cases - I guess obvious ones are things like modding, and some games might be built around user-level scripting. My own use case is not really a game, but requires the user to be able to write short scripts to move objects around (a bit like Logo, in a way!) and using Lua for this feels like a good fit as it has a simple syntax for simple code, but also allows writing much more complex code if the user needs to.

    Getting the script data into the game is another matter - currently I'm using HTML form fields and Javascript to inject the script data into the Unity player, but native apps obviously have more flexibility there.
     
    Last edited: Jun 15, 2012
  2. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,039
    I could think of some situations where this might be useful, yeah. I don't have a current need for it, but I could see myself wanting it in the future, maybe.
     
  3. hima

    hima

    Joined:
    Oct 1, 2010
    Posts:
    183
    Have you looked at the asset store? I think one guy implemented something like this, but it only works on Windows. It would be awesome if you could make it works on both Windos and Mac!

    As for usecases, I think using Lua will really help with a lot of things. Level creation is one thing for sure. Using lua files to create levels would be much easier to fix and patch the game. Instead of having to upload the whole big executable file, we can upload the fixed lua files.

    I need a solution that works on both Mac and PC, so I'm currently using the python one on asset store, and the javascript with Jurassic Engine.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You don't have to do that anyway; the executable for Unity is fixed and doesn't change with your scripts. If you look in the data for a game you will see things like (depending on what language(s) you used) "Assembly - UnityScript.dll" and "Assembly - CSharp - first pass.dll", which are typically a few dozen to a few hundred KB depending on how big your scripts are.

    --Eric
     
  5. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    As the interpreter has been ported to C#, it should work on any platform - I've tested on Mac, PC, and web player, but I don't have licenses for iOS etc.

    Here's an example webplayer app: http://www.gfootweb.webspace.virginmedia.com/LuaDemo/

    Initially the scene is empty, but if you press "Send Code" it will send the sample code from the web page to the app, which executes it in the Lua interpreter, and it will create and animate a cube. Note that you can do pretty much anything you like in the Lua code. The code block is executed as soon as you send it, and any update(dt) function it defines gets called from a FixedUpdate method in a MonoBehaviour.
     
  6. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,039
    Nicely done!
     
  7. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Me Like!

    This is much more useful than my brainfuck interpreter :p

    Do you intend to release your code?

    Edit: Crashing the code is fun - it makes the a new block, freezing it in position and rotation [as they are determined by time]- leading to a colorful block tower!
     
    Last edited: Feb 23, 2012
  8. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    You're not really crashing it, it's just that every time you press the button the script makes a new cube, overwriting the 'cube' variable, and so the update() function no longer moves the old cube around. If you delete or comment out that line then you can just change the update() function iteratively without constantly making new cubes. This is all just artifacts of the silly way I hooked it up for the demo.

    I'll check the licences of the libraries, but I doubt there are any restrictions so I can probably put it on the asset store or a web site sometime.

    The Lua interpreter on the asset store looks similar to this - it's also based on LuaInterface, but with the standard C back end. It's probably more efficient as a result. It may be possible to extend that one to support both back ends, depending on platform.
     
  9. hima

    hima

    Joined:
    Oct 1, 2010
    Posts:
    183
    Wow! Thank you so much for this. Is there anywhere we can find out more about these information? For example, changing some value inside the prefab, what would that affect the output?

    Awesome! And I'm really happy to hear that it works on Mac and PC. Really looking forward to this!
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Prefab info is presumably in the .assets files. Hex editors are good for poking around in files....

    --Eric
     
  11. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    I should clarify that I was trying to crash it [assigning a string to a vector] but you're correct, the activity I observed appears to have nothing to do with the bug I introduced.

    Very interesting.
     
  12. Nems

    Nems

    Joined:
    Jul 18, 2011
    Posts:
    65
    Looks very good !
    I am looking forward for the source code.

    Is there a way to limit the authorized instructions ?
    Like block access to Camera...
    Even it would be possible by parsing the lua script with string function, I am asking for an automatic way.

    Thanks for sharing
     
  13. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    I think most of the code is under the MIT license, so it should be OK to publish it. At present KopiLua needs to be compiled in Visual Studio, as it requires some defines to be set; these could be replicated at the top of each source file, allowing all the source to be used directly in Unity. As it stands I'm just copying the DLLs into the Unity project though, which works fine - it doesn't make much difference really. You could extract them from the WebPlayer.unity3d file I uploaded if you want to get a head start.

    By default LuaInterface defines a "luanet" variable in the Lua interpreter, which Lua code can use to access arbitrary assemblies - this is the bit that lets the code do whatever it likes. But you can undefine it, e.g.

    Code (csharp):
    1.  
    2.     var L = new Lua();
    3.     L["luanet"] = null;
    4.  
    However, I believe if you allow direct access to any .NET type (e.g. a GameObject) then it's possible for the script to access arbitrary things from the same assembly, and other assemblies if things cascade. So if you want to be sure about these things, you might want to not use LuaInterface at all - just use KopiLua directly. You'd lose all the magic that you didn't want, and could be more confident that the Lua code could only fiddle with things you'd explicitly provided to it.
     
  14. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,649
    Wooo!!!. Very interesting, indeed ;)
     
  15. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    I would be interested in this since I use LuaInterface and although I can bring the the LuaInterface library just fine in the projects, I can't create a LUA hook without object not defined type errors and other errors from the Unity engine, but this is with 3.5.0.
     
  16. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    I've uploaded a zip here, including source code and the demo Unity project I'm using, with precompiled DLLs. It's pretty shabby, but I figured it was better to upload something than nothing!

    http://www.gfootweb.webspace.virginmedia.com/KLI-1.0.zip

    Please read the README.txt.
     
  17. Dylan Fitterer

    Dylan Fitterer

    Joined:
    Apr 29, 2010
    Posts:
    9
    Thanks! I'm looking forward to trying this out in my project.

    A useful trick for reloading Lua files at runtime is to create objects only if they haven't yet been created. That way you can make changes to the code while it's running and get immediate results without spawning multiples.

    For example, change the first line of code in your web example to this:

    cube = cube or UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube)

    Then you can mess with the update function and resend it while the game runs.
     
  18. Dylan Fitterer

    Dylan Fitterer

    Joined:
    Apr 29, 2010
    Posts:
    9
    I added some exception handling and access to audio spectrum data. The result is a little livecoding website where you can code your own music visualizer while you watch it take shape.

    http://bestgameever.com/projects/LivecodeVisualizer/index.html

    Just follow the link and click "Load code" to watch the default visualizer. Then you can mess with the code and reload it to see your changes.

     
  19. Johnnyr

    Johnnyr

    Joined:
    Jun 1, 2009
    Posts:
    58
    Could you elaborate on this? How would I just use KopiLua with a unity project, and if you have time, could you provide an example of implementing it? (as far as explicity telling lua what it can do)

    I'm looking to implement a programming language within unity, but don't need it to even have anything to do with UnityEngine, just a totally separate and custom language, who's commands are then taken and then processed by Unity.

    I'm also not looking for this to be real-time, but scripts that have already been written and are simply loaded and run in unity.

    Perhaps this isn't the right application for LuaInterface?

    Either way, Great work!
     
    Last edited: Apr 4, 2012
  20. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Very nice! Sorry I didn't see it earlier, I find the forum's email notifications are a bit unreliable.

    How did you capture 'print' output - any special way? Also what did you mean about exception handling? I didn't really follow the way the Lua wrappers deal with this - the whole call vs pcall thing. For debugging I often set the #defines to make it just throw exceptions as soon as errors occur instead of passing them up through the API - much easier to trace that way.
     
  21. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    I don't really have time to go into so many details, and in any case I'm not an expert on Lua interfacing - I just glued these libraries together.

    Basically, though, the code I posted is comprised of three DLLs - KopiLua, KopiLuaDLL, and LuaInterface. The second one is a loose wrapper around the first - historically, the first library was a static compiled library, and the second was the DLL wrapper around that static library. KopiLua retains this kind of vestigial split. LuaInterface is simply a higher level library built on the other two.

    So if you want to use KopiLua but not LuaInterface, you can use just KopiLua, or KopiLua with KopiLuaDLL, fairly easily by using the standard Lua API calls. At the very least, you need to create a Lua state object (by asking KopiLuaDLL to do it for you), then you can execute code in it. If you want standard Lua libraries to be available, you need to provide those too, and if you want to give it access to any C# objects you need to jump through a bunch of hoops. I'm not an expert on this, but if I were you I'd read the LuaInterface source to get a feel for some ways to do this. Also consider downloading the original KopiLua zip and looking at its example code.

    You can do this with KopiLua, with or without LuaInterface. But if the scripts are pre-authored, not user-generated, you should consider just using .NET DLLs, if you have that option - it will be easier to debug and more efficient to execute. Most of Unity's target platforms support this one way or another.
     
  22. Rod-Galvao

    Rod-Galvao

    Joined:
    Dec 12, 2008
    Posts:
    210
    Does it have the Lua APIs available (eg. math etc)?

    TIA,
    R.
     
    Last edited: Jun 2, 2012
  23. Jacksendary

    Jacksendary

    Joined:
    Jan 31, 2012
    Posts:
    408
    sorry but not much new in this, lua have been implemented in C# for a longer time now so it easily could work between lua and C# but i will look forward to see if this is working better :)
     
  24. kersk

    kersk

    Joined:
    Jan 2, 2012
    Posts:
    56
    Hi George,

    First of all, great work on KLI -- it's really useful!

    I started playing around with the examples you included in the .zip, namely "KLITest.cs". I'm running into an issue where it runs perfectly for about a minute, and then it suddenly stops working and starts throwing exceptions. I suspect it may be some sort of issue with the memory management in the LuaVM. I was wondering if you had encountered anything like this and if you had any ideas on how to resolve this. I'm using Unity 3.5.2f2 -- here are the stack traces for the exceptions that I'm running into:



    Exception: Exception of type 'System.Exception' was thrown.
    KopiLua.Lua.Assert (Boolean condition)
    KopiLua.Lua.lua_assert (Boolean c)
    KopiLua.Lua.luaC_step (KopiLua.lua_State L)
    KopiLua.Lua.luaC_checkGC (KopiLua.lua_State L)
    KopiLua.Lua.lua_pushlstring (KopiLua.lua_State L, KopiLua.CharPtr s, UInt32 len)
    KopiLua.Lua.lua_pushstring (KopiLua.lua_State L, KopiLua.CharPtr s)
    KopiLua.Lua.luaL_getmetafield (KopiLua.lua_State L, Int32 obj, KopiLua.CharPtr event_)
    KopiLua.Lua.luaB_getmetatable (KopiLua.lua_State L)
    KopiLua.Lua.luaD_precall (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nresults)
    KopiLua.Lua.luaV_execute (KopiLua.lua_State L, Int32 nexeccalls)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.callTMres (KopiLua.lua_State L, KopiLua.lua_TValue res, KopiLua.lua_TValue f, KopiLua.lua_TValue p1, KopiLua.lua_TValue p2)
    KopiLua.Lua.luaV_gettable (KopiLua.lua_State L, KopiLua.lua_TValue t, KopiLua.lua_TValue key, KopiLua.lua_TValue val)
    KopiLua.Lua.luaV_execute (KopiLua.lua_State L, Int32 nexeccalls)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.f_call (KopiLua.lua_State L, System.Object ud)
    KopiLua.Lua.luaD_rawrunprotected (KopiLua.lua_State L, KopiLua.Pfunc f, System.Object ud)
    KopiLua.Lua.luaD_pcall (KopiLua.lua_State L, KopiLua.Pfunc func, System.Object u, Int32 old_top, Int32 ef)
    KopiLua.Lua.lua_pcall (KopiLua.lua_State L, Int32 nargs, Int32 nresults, Int32 errfunc)
    Lua511.LuaDLL.lua_pcall (KopiLua.lua_State luaState, Int32 nArgs, Int32 nResults, Int32 errfunc)
    LuaInterface.Lua.DoString (System.String chunk)
    KLITest.Update () (at Assets/KLITest.cs:67)



    Exception: Exception of type 'System.Exception' was thrown.
    KopiLua.Lua.Assert (Boolean condition)
    KopiLua.Lua.lua_assert (Boolean c)
    KopiLua.Lua.luaC_step (KopiLua.lua_State L)
    KopiLua.Lua.luaC_checkGC (KopiLua.lua_State L)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.callTMres (KopiLua.lua_State L, KopiLua.lua_TValue res, KopiLua.lua_TValue f, KopiLua.lua_TValue p1, KopiLua.lua_TValue p2)
    KopiLua.Lua.luaV_gettable (KopiLua.lua_State L, KopiLua.lua_TValue t, KopiLua.lua_TValue key, KopiLua.lua_TValue val)
    KopiLua.Lua.luaV_execute (KopiLua.lua_State L, Int32 nexeccalls)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.f_call (KopiLua.lua_State L, System.Object ud)
    KopiLua.Lua.luaD_rawrunprotected (KopiLua.lua_State L, KopiLua.Pfunc f, System.Object ud)
    KopiLua.Lua.luaD_pcall (KopiLua.lua_State L, KopiLua.Pfunc func, System.Object u, Int32 old_top, Int32 ef)
    KopiLua.Lua.lua_pcall (KopiLua.lua_State L, Int32 nargs, Int32 nresults, Int32 errfunc)
    Lua511.LuaDLL.lua_pcall (KopiLua.lua_State luaState, Int32 nArgs, Int32 nResults, Int32 errfunc)
    LuaInterface.Lua.DoString (System.String chunk)
    KLITest.Update () (at Assets/KLITest.cs:66)



    IndexOutOfRangeException: Array index is out of range.
    KopiLua.Lua+CallInfo.get_Item (Int32 offset)
    KopiLua.Lua+CallInfo.inc (KopiLua.CallInfo value)
    KopiLua.Lua.traversestack (KopiLua.global_State g, KopiLua.lua_State l)
    KopiLua.Lua.propagatemark (KopiLua.global_State g)
    KopiLua.Lua.singlestep (KopiLua.lua_State L)
    KopiLua.Lua.luaC_step (KopiLua.lua_State L)
    KopiLua.Lua.luaC_checkGC (KopiLua.lua_State L)
    KopiLua.Lua.lua_pushlstring (KopiLua.lua_State L, KopiLua.CharPtr s, UInt32 len)
    KopiLua.Lua.lua_pushstring (KopiLua.lua_State L, KopiLua.CharPtr s)
    KopiLua.Lua.luaL_getmetafield (KopiLua.lua_State L, Int32 obj, KopiLua.CharPtr event_)
    KopiLua.Lua.luaB_getmetatable (KopiLua.lua_State L)
    KopiLua.Lua.luaD_precall (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nresults)
    KopiLua.Lua.luaV_execute (KopiLua.lua_State L, Int32 nexeccalls)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.callTMres (KopiLua.lua_State L, KopiLua.lua_TValue res, KopiLua.lua_TValue f, KopiLua.lua_TValue p1, KopiLua.lua_TValue p2)
    KopiLua.Lua.luaV_gettable (KopiLua.lua_State L, KopiLua.lua_TValue t, KopiLua.lua_TValue key, KopiLua.lua_TValue val)
    KopiLua.Lua.luaV_execute (KopiLua.lua_State L, Int32 nexeccalls)
    KopiLua.Lua.luaD_call (KopiLua.lua_State L, KopiLua.lua_TValue func, Int32 nResults)
    KopiLua.Lua.f_call (KopiLua.lua_State L, System.Object ud)
    KopiLua.Lua.luaD_rawrunprotected (KopiLua.lua_State L, KopiLua.Pfunc f, System.Object ud)
    KopiLua.Lua.luaD_pcall (KopiLua.lua_State L, KopiLua.Pfunc func, System.Object u, Int32 old_top, Int32 ef)
    KopiLua.Lua.lua_pcall (KopiLua.lua_State L, Int32 nargs, Int32 nresults, Int32 errfunc)
    Lua511.LuaDLL.lua_pcall (KopiLua.lua_State luaState, Int32 nArgs, Int32 nResults, Int32 errfunc)
    LuaInterface.Lua.DoString (System.String chunk)
    KLITest.Update () (at Assets/KLITest.cs:67)
     
  25. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Ouch. I fixed some issues last year in the garbage collector, and the call stacks look familiar, but I don't have the fixed code as I no longer work there.

    If you have a lua script that causes this consistently then it might help in finding the problem, but in any case I'm not sure that I'll be debugging it any time soon. Debugging other people's hard-to-read code is a bit too close to my day job at the moment, not really something I want to do for fun at home!

    If you want to debug it yourself, dig into the lua garbage collector and figure out what those methods actually do. It was a bit of a slog doing this last year, but in the end I think the fixes were relatively minor and resulted in much better stability, though we never used it in practice so didn't throw many complicated scripts at it.
     
  26. kersk

    kersk

    Joined:
    Jan 2, 2012
    Posts:
    56
    Thanks for the tips!

    Just to clarify though, I am running into this with the unmodified included example found in "Unity/KLITest/Assets/KLITest.cs".

    Here is a more slimmed down version of that script that is still displaying the same problem:

    Code (csharp):
    1. using UnityEngine;
    2. using LuaInterface;
    3.  
    4. public class KLITest : MonoBehaviour
    5. {
    6.     private Lua L;
    7.  
    8.     void Start()
    9.     {
    10.         L = new Lua();
    11.         L.DoString("UnityEngine = luanet.UnityEngine");
    12.         L.DoString("cube = UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube)");
    13.     }
    14.    
    15.     void Update()
    16.     {
    17.         L.DoString("t = UnityEngine.Time.realtimeSinceStartup");
    18.         L.DoString("q = UnityEngine.Quaternion.AngleAxis(t*50, UnityEngine.Vector3.up)");
    19.         L.DoString("cube.transform.rotation = q");
    20.     }
    21. }
    It will run great for about a minute and then explode. I feel like using luanet accelerates how quickly the problem arises... probably just because it is pushing the garbage collector harder.

    I really would like to put this system to use in a game, but as it is right now I'm hesitant to build anything on top of it. It's a shame for all this work to go to waste if it's just a few minor bugs causing this instability. Diving into this system blind to try to fix this sounds pretty daunting, but if you have any more detailed tips or ideas on what you think the issue might be, I'm willing to give it a shot.
     
  27. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    I remember problems with the "user" data type in Lua, which is how things like C# types, classes, etc get presented to the Lua code. In C, at least with the weird DLL wrapper, you're restricted to using four-byte integers for these things, and it's kind of weird how that was translated into C#. Of course, in C# we could just pass object references in and let the Lua interpreter hang on to those.

    I don't remember exactly though. One problem was that it would sometimes screw up the garbage collector's asserts because it makes assumptions - sometimes incorrect ones - about these things.

    I might find some time to have a look tonight though, I am curious now.
     
  28. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    I think I've fixed this now. There were problems with the VM's notion of how much memory had been allocated - specifically, whenever it allocated "userdata", it didn't increase the total allocation size, but when it frees userdata it does reduce the allocation size. This led to problems when the size wrapped at zero, triggering asserts in the garbage collector, which assumed that after performing collection less memory ought to be in use.

    Your third callstack might still be something else. I haven't been able to reproduce it.

    I've uploaded a new archive with the bug fix and a couple of other cosmetic changes (PDB/MDB files, switched to .meta files, and so on).

    http://www.gfootweb.webspace.virginmedia.com/KLI/KLI-1.0a.zip
     
  29. kersk

    kersk

    Joined:
    Jan 2, 2012
    Posts:
    56
    Awesome!

    I'll give it a shot first thing tomorrow morning.
     
  30. kersk

    kersk

    Joined:
    Jan 2, 2012
    Posts:
    56
    The fix is looking good! Everything seems to be working and no explosions so far.

    I'll start really pushing it over the next few days to see how it goes.

    Also, I was looking over the changes you made and I agree with your commented out fix at lstring.cs#135:

    Code (csharp):
    1. u.uv.len = 0; /* gfoot: not sizeof(t)? */
    That definitely looks like an open bug to me. I did a cursory check of what was actually using that code path, and I only saw it being used internally with file io.. so that's probably why it hasn't popped up yet. And I'm also thinking we're not seeing the issue because it's only heading towards the problem at the rate of small and infrequent sizeof(t) allocations instead of the much larger and more frequent userdata allocations. I'll try to test this and follow up on it next week.

    Anyway, I just wanted to say thanks for taking a look at this so quickly. I doubt I would have been able to pinpoint this problem, at least not without a ton of hard work and time that I don't have. :)

    BTW, I think this whole project should be up on github -- it's really handy to be able to see how these kind of changes were made over time, and it would help get some more visibility for this cool project. You should definitely put it up there... so hurry up already! :)
     
  31. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Well, the problem doesn't only occur with large allocations - when you're going through LuaInterface, userdata is only used in 4-byte chunks, yet the bug still occured fairly quickly.

    KopiLua also doesn't try to attribute the right amount of memory here - it tries to attribute the same amount of memory that the C implementation would have used. So it adds a 24-byte overhead for any userdata plus the data's size. It's not obvious what it should do in this case because this whole function doesn't exist in the C implementation - I guess it depends how file handling is done in the C version really, because that's what it would like to simulate.

    Personally I don't value that level of fidelity as much as KopiLua's author did - I'd prefer the library to be fast rather than consistent with the C version. However, I don't want to dive in and change all that until it's completely stable.

    So going back to the memory attribution, other than the desire to emulate the C version, the really critical thing is that however much memory we tell the GC we've used here, has to match how much we tell it we've freed later on (in freeobj). I think this would be wrong in this case.

    It should be possible to allocate one of these things, then 'forget' the reference to it, then trigger a GC pass and notice that the amount of memory in use is wrong. It won't trigger the same bug as before though because in this case we're claiming to allocate more than we claim to free - the opposite of the bug you found before, which was more obvious as the amount of allocated memory quickly went negative and triggered asserts.

    It's no problem, I guess I already knew where to look in the end. The next thing I'm worried about is string handling, as I seem to remember some problems with that last year too! Again due to the way KopiLua tries to pretend the amount of memory used by an object matches the C version.

    Yeah. KopiLua is already on github (unofficially I think), I wasn't sure what to do with this - whether I should fold my changes back into that one, or make a new one or something. It's complicated because I'd rather have one git repo containing KopiLuaInterface as well as KopiLua, so it's not really a straight branch of the KopiLua repo.
     
  32. kersk

    kersk

    Joined:
    Jan 2, 2012
    Posts:
    56
    I guess you could make a fork of the KopiLua repo that is already on GitHub, reapply your changes to your fork, and then make a separate repo for KLI that has your KopiLua fork referenced as a git submodule?

    Or you could just throw the entire KLI project up there as a whole, that would be the easiest and most straightforward. :)
     
  33. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,551
    Seems like George went ahead and made a few repos:
    https://github.com/gfoot/kopilua
    https://github.com/gfoot/kopiluainterface

    Though the example Unity project seems to be missing.



    To anyone dealing with this, KopiLua is a direct conversion of the Lua C library, so any tutorial on how to use the Lua C API will apply, when it comes to using KopiLua.

    I'd prefer something in between KopiLua and KopiLuaInterface, have it relatively easy to define which areas of my code will be exposed to Lua (no need to touch the Lua API directly), but expose nothing else (i.e. UnityEngine, everything in Mono).

    I'd really like to make some code that would do that sometime.


    Taking a quick look, I think you can edit LuaInterface for this.

    Removing LuaInterface.ObjectTranslator.loadAssembly (which uses this http://msdn.microsoft.com/en-us/library/system.reflection.assembly.load(v=vs.71).aspx) is probably a start.

    (From what I understand, LuaInterface.ObjectTranslator takes care of automatically converting C# classes into Lua classes and vice-versa.)

    Potentially, that means Lua won't understand any C# class/struct automatically anymore (stuff like Vector3). You'll either need to pass a Vector3 as 3 floats (x, y, z) or somehow describe to Lua what a Vector3 is (perhaps using some way to explicitly "register" your classes/structs to Lua, via implementing an interface http://msdn.microsoft.com/en-us/library/87d83y5b(v=vs.80).aspx).
     
  34. George Foot

    George Foot

    Joined:
    Feb 22, 2012
    Posts:
    399
    Those repos are not Unity-friendly yet - I removed some of that stuff before committing on the fork, to minimize the initial change set. I also don't know whether I did the sub-module thing properly in git...

    Rather than removing ObjectTranslator, maybe you could start by just not setting the "luanet" variable. This would prevent the user from pulling in arbitrary assemblies. If you provided a GameObject in a Lua variable, I did worry that the user might be able to somehow access other types. For example, could the user go from gameObject to GameObject to GameObject.CreatePrimitive? I think not, as the first step can't be done, but it's hard to be sure.

    Another approach would be to leave LuaInterface as it is, but add checks to it, so any time it's about to expose something to the Lua code, it calls your function first. You can then whitelist the objects, methods, etc, that you want it to expose. So for example, given a component with a reference to a "target" object, you might want the Lua code to be able to change the target, but not look through it - or to only see certain information about the target, and not have the ability to change it much (or delete it...)

    Overall, though, it might be easier to just do this more traditionally, designing the interface to the Lua code more carefully and explicitly setting up the Lua tables to expose specific C# functions.
     
  35. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,551
    Just so you'd know, KopiLua gets an exception when running this file: http://en.literateprograms.org/inde...nloadCode/Fibonacci_numbers_(Lua)&oldid=15146

    Specifically, its that metafib thing in that file that makes the error. I'm not proficient enough in Lua to know what exactly it does and why KopiLua can't make it work, but I've narrowed it down to this:

    Code (csharp):
    1.  
    2. function test(t, ...)
    3.     local args = {...} -- this is the error
    4.     -- some other code
    5. end
    6.  
    This is Lua's way to specify a variable number of arguments, but I'm not sure what that code is trying to do.

    Here's the call stack. Take note its not a LuaException, so this probably shouldn't have happened in the first place.
    Code (csharp):
    1.  
    2. System.Exception: Exception of type 'System.Exception' was thrown.
    3.   at KopiLua.Lua.Assert (Boolean condition) [0x00000] in <filename unknown>:0
    4.   at KopiLua.Lua.lua_assert (Int32 c) [0x00000] in <filename unknown>:0
    5.   at KopiLua.Lua.close_func (KopiLua.LexState ls) [0x00000] in <filename unknown>:0
    6.   at KopiLua.Lua.body (KopiLua.LexState ls, KopiLua.expdesc e, Int32 needself, Int32 line) [0x00000] in <filename unknown>:0
    7.   at KopiLua.Lua.simpleexp (KopiLua.LexState ls, KopiLua.expdesc v) [0x00000] in <filename unknown>:0
    8.   at KopiLua.Lua.subexpr (KopiLua.LexState ls, KopiLua.expdesc v, UInt32 limit) [0x00000] in <filename unknown>:0
    9.   at KopiLua.Lua.expr (KopiLua.LexState ls, KopiLua.expdesc v) [0x00000] in <filename unknown>:0
    10.   at KopiLua.Lua.recfield (KopiLua.LexState ls, KopiLua.ConsControl cc) [0x00000] in <filename unknown>:0
    11.   at KopiLua.Lua.constructor (KopiLua.LexState ls, KopiLua.expdesc t) [0x00000] in <filename unknown>:0
    12.   at KopiLua.Lua.simpleexp (KopiLua.LexState ls, KopiLua.expdesc v) [0x00000] in <filename unknown>:0
    13.   at KopiLua.Lua.subexpr (KopiLua.LexState ls, KopiLua.expdesc v, UInt32 limit) [0x00000] in <filename unknown>:0
    14.   at KopiLua.Lua.expr (KopiLua.LexState ls, KopiLua.expdesc v) [0x00000] in <filename unknown>:0
    15.   at KopiLua.Lua.explist1 (KopiLua.LexState ls, KopiLua.expdesc v) [0x00000] in <filename unknown>:0
    16.   at KopiLua.Lua.localstat (KopiLua.LexState ls) [0x00000] in <filename unknown>:0
    17.   at KopiLua.Lua.statement (KopiLua.LexState ls) [0x00000] in <filename unknown>:0
    18.   at KopiLua.Lua.chunk (KopiLua.LexState ls) [0x00000] in <filename unknown>:0
    19.   at KopiLua.Lua.luaY_parser (KopiLua.lua_State L, KopiLua.Zio z, KopiLua.Mbuffer buff, KopiLua.CharPtr name) [0x00000] in <filename unknown>:0
    20.   at KopiLua.Lua.f_parser (KopiLua.lua_State L, System.Object ud) [0x00000] in <filename unknown>:0
    21.   at KopiLua.Lua.luaD_rawrunprotected (KopiLua.lua_State L, KopiLua.Pfunc f, System.Object ud) [0x00000] in <filename unknown>:0
    22.   at KopiLua.Lua.luaD_pcall (KopiLua.lua_State L, KopiLua.Pfunc func, System.Object u, Int32 old_top, Int32 ef) [0x00000] in <filename unknown>:0
    23.   at KopiLua.Lua.luaD_protectedparser (KopiLua.lua_State L, KopiLua.Zio z, KopiLua.CharPtr name) [0x00000] in <filename unknown>:0
    24.   at KopiLua.Lua.lua_load (KopiLua.lua_State L, KopiLua.lua_Reader reader, System.Object data, KopiLua.CharPtr chunkname) [0x00000] in <filename unknown>:0
    25.   at KopiLua.Lua.luaL_loadfile (KopiLua.lua_State L, KopiLua.CharPtr filename) [0x00000] in <filename unknown>:0
    26.   at Lua511.LuaDLL.luaL_loadfile (KopiLua.lua_State luaState, System.String filename) [0x00000] in /Users/.../Assets/Packages/Scripts/KLI/KopiLuaDll/LuaDLL.cs:534
    27.   at LuaInterface.Lua.DoFile (System.String fileName) [0x0000c] in /Users/.../Assets/Packages/Scripts/KLI/KopiLuaInterface/Lua.cs:241
    28.   at LuaInterfaceTest.Start () [0x004e8] in /Users/.../Assets/Packages/Scripts/KLI/Test/Scripts/LuaInterfaceTest.cs:99
    29. UnityEngine.Debug:LogError(Object)
    30. LuaInterfaceTest:Start() (at Assets/Packages/Scripts/KLI/Test/Scripts/LuaInterfaceTest.cs:167)
    31.  
    32.  
    What's odd is normal Lua runs that script fine.
     
  36. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,551
    Here's my attempt at displaying user-friendly error messages:

    Code (csharp):
    1.  
    2.         try
    3.         {
    4.             lua.DoFile(scriptName);
    5.         }
    6.         catch (KopiLua.Lua.LuaException e)
    7.         {
    8.             // fail gracefully
    9.            
    10.             if (e.c.status == KopiLua.Lua.LUA_ERRSYNTAX)
    11.             {
    12.                 output += "Syntax error." + "\n\n";
    13.             }
    14.             else if (e.c.status == KopiLua.Lua.LUA_ERRRUN)
    15.             {
    16.                 output += "LUA_ERRRUN" + "\n\n";
    17.             }
    18.             else if (e.c.status == KopiLua.Lua.LUA_ERRMEM)
    19.             {
    20.                 output += "LUA_ERRMEM" + "\n\n";
    21.             }
    22.             else if (e.c.status == KopiLua.Lua.LUA_ERRERR)
    23.             {
    24.                 output += "Error in error handling." + "\n\n";
    25.             }
    26.             lua.DoString("err = debug.traceback()");
    27.             output += lua.GetString("err") + "\n";
    28.         }
    29.  
    I was hoping I could print out the line number of the Lua script where the error happened, but not sure how to do that. Anyone got ideas?
     
  37. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I've fixed that bug before, in the version on github, but that version is still not 100% Unity-friendly, I got bored again. :) I'll try to update the Unity-specific package sometime. The fix was just to disable some checking code that makes sure a function definition is correctly parsed - for whatever reason, the checking code doesn't work on varargs functions. In the github version it was commenting out line 457 of src/lparser.cs.

    I don't know much about Lua error reporting either. You're meant to register a Lua function to call in case of errors, which probably gets the script "name" and line number. In KLI the name probably won't mean much, as we don't really support loading from raw files.

    I'm not sure what that does for C# exceptions in the Lua interpreter - I think KopiLua tries to catch them and emit calls to the Lua error handler function, but I usually just turn that off so I can properly see in the debugger what's going wrong in the interpreter.
     
  38. gaodoo@gmail.com

    gaodoo@gmail.com

    Joined:
    Oct 26, 2012
    Posts:
    1
    I am a user of kopiluainterface .
    thanks for you great job .

    when i used it in unity3d , one question confused me .

    the offical luainterface support unicode.
    but it seems kopiluainterface do not support unicode well .

    for example :
    in offical LuaInterface , we could write :
    -------------------------------------
    Lua l = new Lua();
    l.DoString("print('KopiLuaInterface 很棒')");
    -----------------------------------------
    and it works good .

    but when i use kopiluainterface.
    it do not work .


    --------------------------
    so . can you give me some help about my trouble .............
    i'll wait for your answers........................
     
    Last edited: Nov 6, 2012
  39. huaiyao

    huaiyao

    Joined:
    Nov 20, 2012
    Posts:
    4
    How can I use this in IOS ?
    Thank you for your reply.
     
  40. jonbro5556

    jonbro5556

    Joined:
    Jan 1, 2013
    Posts:
    24
    I am not the dev, but I think the issue might reside in kopiLua, as far as I can tell it doesn't fully support unicode.

    I just wanted to say, thanks very much for your work on this. I haven't used it, but it seems like a totally useful thing for some project in the future.
     
  41. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    As my user account name changed on the forums, I can no longer update the original post...

    I want to add that I made some stability fixes in September, but forgot to release new binaries. You can get them here now:


    Or clone the git repo (or download the zip) and build it yourself in Visual Studio:


    Also, at the suggestion of a user, I investigated getting Lua remote debugging to work. This was kind of deeper than I expected, because it depends on socket support and that's not a core Lua feature, so I had to make a managed version of some bits of the luasocket library, but I got it working in the end. It is rough, and not 100% stable, but I'd be interested in any feedback on it:


    The debugging works through the mobdebug library, which is in particular used by the ZeroBrane IDE, and this provides a comfortable way to edit and debug Lua code. It's worth checking out the tutorial videos on their website - the live coding stuff looks really cool and should totally be possible with Unity.
     
  42. beck

    beck

    Joined:
    Nov 23, 2010
    Posts:
    294
    gfoot, thanks for your diligence in supporting KopiLua :) I have been plagued with GC bugs while integrating Lua the last two months, which were all fixed (so far) after updating to the version you recently posted. I'm now able to continue development on my lua integration without issue. I'm also happy to see your explorations into remote debugging, once I've solidified my integration I'm going to give it a shot and I'll post my remarks here. Thanks again!
     
  43. Gamars

    Gamars

    Joined:
    Aug 16, 2013
    Posts:
    14
    Hey man!! That's wonderful!!!

    But I met a problem!
    I have a class named "MyClass". And how to let lua knows the class??

    I try to use luanet.MyClass or add a namespace to it (like luanet.UnityEngine.MyClass) but all return a nil value.
    I'm a newer , Please help me!!

    Thank you!!!!
     
  44. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Hi Gamars,

    Generally the way you use luanet is:

    luanet.AssemblyName.Any.Namespaces.Here.Class

    Your assembly name might be AssemblyCSharp or something like that, I'm not sure. Also, the mechanism LuaInterface uses to do this might not work so well for Unity user code, at least not on all platforms.

    By far the easiest way to do this, though, is to feed the data into the Lua interpreter from the C# side. The demo app I posted does this when it initializes the Lua interpreter:

    Code (csharp):
    1.  
    2.         _lua = new Lua();
    3.         _lua.DoString("UnityEngine = luanet.UnityEngine");
    4.         _lua.DoString("System = luanet.System");
    5.         _lua["gameObject"] = this;
    6.  
    The two DoString lines are just executing Lua code, aliasing the UnityEngine and System assemblies to simpler names, so the user code doesn't need to explicitly write "luanet" to use those. The last line sets a Lua variable called "gameObject" to reference the MonoBehaviour that's doing all this (so it's not really a GameObject after all). That means that the Lua code could now write things like gameObject:GetComponent() or similar to call a method on the MonoBehaviour.

    But you asked about referencing a class - so I'll assume you mean the class itself, and not an instance of the class. I'm pretty sure the syntax in the last line would work for that too, you'd need to use typeof though. So something like this maybe?

    Code (csharp):
    1.  
    2.     _lua["SomeClass"] = typeof(SomeClass);
    3.  
    Then I think there's some weird LuaInterface syntax for constructing a new object of that type which I don't recall at the moment.
     
  45. npsf3000

    npsf3000

    Joined:
    Sep 19, 2010
    Posts:
    3,830
    Has anyone tried this on mobile - in particular iOS?
     
  46. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Yes, I tested it on desktop, web player, iOS, and Android. I tested a predecessor on Xbox 360, but I no longer have a license for that now.

    It's also being used in Pixel Crushers' Dialogue System for Unity (http://forum.unity3d.com/threads/204752-Dialogue-System-for-Unity) and TonyLi and his users have probably tested it more widely than I have.
     
  47. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    Yup, it's been run in games and applications on all those platforms. George has put together a really solid, reliable Lua implementation for Unity. I still need to build a link.xml for iOS Pro users to be able to do bytecode stripping, but that's as much a Dialogue System issue as anything else. In fact, npsf3000, if you have iOS Pro, I'm looking to hire someone to build and test the link.xml file. If you're interested, please PM me.
     
    Last edited: Jan 24, 2014
  48. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    I'm just learning how to use KopiLua and KopiLuaInterface with Unity and have been following this tutorial:

    http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/

    [h=2]Showing a Form[/h] Showing a form is very straightforward, once you have brought in the necessary assembly, and the Form type itself.

    -- form1.wlua require 'luanet' luanet.load_assembly "System.Windows.Forms" Form = luanet.import_type "System.Windows.Forms.Form" form = Form() form.Text = "Hello, World!" form:ShowDialog()
    Instead of using Windows forms. How could I set up KopiLuaInterface to use DaikonForge or NGUI.

    Any help is greatly appreciate it.

    Cheers.
     
  49. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    Got the answer by studying the example unity project from
    http://gfootweb.webspace.virginmedia.com/LuaDemo/

    The examples from George's Unity demo package is Awesome. Very clear and easy to understand.

    Big thumbs up for the great work.

    Cheers.
     
  50. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    I would like to run a lua application that has multiple ".lua" files using KopiLua but do not know if this is possible.
    Is there a way to do "require" in KopiLuaInterface ?

    require "luafile"

    Cheers.