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. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    Turns out the answer is that KopiLua doesn't know about Unity's file system. The solution is to use George's kopiluadebug project. https://github.com/gfoot/kopiluadebug

    Thanks again George.
     
  2. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    Quite a learning curve so far integrating Lua with Unity.

    Managed to learn quite a bit. Another challenge is how to handle events between Lua and Unity.
    I've been googling quite a bit but not having much success.

    How to do the following:

    From Lua:
    1. Create events and attach Event listeners to Unity's GOs.
    2. When Unity GO's eventListener is triggered, fire the event handler function in Lua.

    Any help is greatly appreciate it.

    Cheers.
     
  3. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    You need some kind of component attached to the GameObject in order to receive any form of event. It isn't really practical to create a bespoke component class from Lua that handles its own choice of Unity entry points, though it could be done in some circumstances. So you really need a generic component to provide the entry point and reflect it through to Lua in whatever way you like.

    Example off the top of my head:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class LuaOnTriggerEnterHandler : MonoBehaviour
    5. {
    6.     public string CodeToRun;
    7.  
    8.     private LuaInstance _luaInstance;
    9.  
    10.     public void Start()
    11.     {
    12.         _luaInstance = GetComponent<LuaInstance>();
    13.     }
    14.  
    15.     public void OnTriggerEnter(Collider otherObject)
    16.     {
    17.         _luaInstance.RunThisCodeFragment(CodeToRun);
    18.     }
    19. }
    20.  
    LuaInstance would be another MonoBehaviour that creates a Lua interpreter instance, and provides a RunThisCodeFragment method. So this behaviour would, on startup, look for a LuaInstance attached to the same GameObject. Then whenever Unity calls the OnTriggerEnter function it tells the LuaInstance to execute whatever code is in CodeToRun.

    This is a poor example, especially as executing a code fragment like that is inelegant and inflexible. But with a bit more structure you can make it precompile the code and track a LuaFunction object instead, and pass 'otherObject' through to that as a parameter, for example. You might also consider having objects in your Lua interpreter which shadow the GameObjects in your scene.

    The problem is that LuaInterface is so flexible there are a million ways you could define this interface, and you really need to pick one you like. It depends a lot of things, in particular where the Lua code comes from (e.g. in the example above, it's edited in the Inspector, but maybe you want to read it from disk, or download it dynamically from a web server, etc).

    Also, instead of defining separate behaviours for the different kinds of events Unity can send to you, you could just have one monolithic behaviour that captures all of them and reflects them through to Lua if a handler is defined. This may be rather inefficient, as a lot of the events may not be handled at the Lua level and Unity would be expending effort in calling your C# methods unnecessarily, but that may or may not matter to you.

    I understand your pain in trying to figure out how to use Lua effectively. It is a common problem, both here and in the Lua world in general - there are so many ways of integrating it into games, there is no one standard way to do it, and this makes it hard to get any focus. I don't have any answers for that - I am not experienced enough with practical use of Lua.

    On that note it may be a good idea to look at some Lua engines elsewhere, and see how Lua is integrated, then use that practical experience to figure out how you'd like to integrate it into your Unity games. I found this page interesting: http://studio.zerobrane.com/tutorials.html Its purpose is to demonstrate use of the debugger and live coding support in the ZeroBrane IDE, but aside from that, the videos give you some exposure to half a dozen different Lua engines, and might help you to pick something you want to study in more detail.
     
  4. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    Thanks very much George for your suggestions.

    Whew, the choices of how to do this is mind boggling and how to implement it in Unity is also a trick pony in itself.

    To break the problem down. I've been focusing on using LUA to create events and attach event listeners to Gameobjects.

    In KopiLuaInterface, the file MethodWrapper.cs contains a number of event related functions and classes.

    I noticed in the readme docs for KopiLuaInterface, you mentioned that you disabled some things to make it work for unity. I'm wondering if these classes are being used and if there is a way to somehow use this functionality to achieve the goal of being able to create events and attach listeners to Gameobjects from Lua.

    /*
    * Wrapperclassforeventsthatdoesregistration/deregistration
    * ofeventhandlers.
    */
    classRegisterEventHandler
    {


    ///<summary>
    ///Wekeeptrackofwhatdelegateswehaveautoattachedtoanevent - toallowustocleanlyexitaLuaInterfacesession
    ///</summary>
    classEventHandlerContainer : IDisposable


    * BasewrapperclassforLuafunctioneventhandlers.
    * Subclassesthatdoactualeventhandlingarecreated
    * atruntime.

     
    Last edited: Feb 12, 2014
  5. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Everything in LuaInterface should work fine, I think. The only things I disabled were in KopiLua - things like certain classes of direct filesystem access, or console access, which don't work in Unity (or don't work on all platforms).

    The trouble with trying to dynamically hook one of Unity's entry points (I'll keep using OnCollisionEnter as an example, but Start, Update, and so on are just the same) is that Unity itself requires a concrete C# class to define the entry point. The only way to decide at runtime which of these entry points you want to hook is to dynamically create a class (not just an instance) at runtime that defines the right entry points, and attach it to the GameObject.

    I haven't tried doing that, but it may be possible using .NET reflection, and if so, then LuaInterface should provide enough access from the Lua side to support it - you can call any methods from Lua that you could call from C#, so your Lua code can call whatever System.Reflection methods you need to define the new class. But in any case, this reflection-heavy technique won't work in the web player, nor on AOT platforms such as iOS, so I don't find it very interesting.

    The alternative is to define a C# class at build time to hook some/all of the entry points and chain through to Lua, and this is probably the best approach. So it does require some C#, but only in a generic way - after that, user-defined code can hook any event for which you have provided a C# wrapper.

    LuaInterface makes it pretty easy to dynamically attach components to GameObjects, of course - that is its job, you just need to call the right APIs. So something like gameObject:AddComponent(...) should work. But the component you're adding must have been defined already, as a C# class.

    For production use though you probably want a decent layer on top of LuaInterface which provides your Lua code with a better-organized, higher-level view of Unity. I started working on a layer to interface better between Lua and Unity, beyond simply allowing them to interact in an explicit fashion (which is what LuaInterface provides) but didn't finish it, it just ended up on my backlog of things it would be nice to finish sometime.
     
  6. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    This sounds like a great idea and the most reasonable thing to do at this time.

    Would you consider sharing the unfinished code, it would really help me to have something to start with and build upon.

    Cheers.
     
  7. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Here is all I have so far on that: http://gfootweb.webspace.virginmedia.com/LuaEvents.zip

    After unzipping it you'll need to supply the three Kopi* DLLs.

    When you run TestScene, you can click on the cube to make it jump, and it changes colour randomly when it hits the ground.

    This is driven by two components attached to the Cube game object - LuaOnClick and LuaOnCollision. They're based on a common base class which provides access to a Lua interpreter (just through a singleton at the moment). You can see in the C# code how those components each hook one Unity entry point and redirect it to run some Lua code, pretty much like the example I pasted in an earlier post.

    The actual code in each case comes from a LuaScript member variable, which is really just a string, and there's an editor script in there that affects the way it is presented in the Inspector, giving you a multi-line box to edit the script in. It is not very polished - to see the script at all you need to click on the label in the Inspector (where it says e.g. "On Click Script"). It also keeps forgetting whether it should be expanded, which is not convenient.

    The point of all this was to be able to write custom event handlers for one-off events in a diverse game world without having to write a bespoke C# script for each one telling it what to trigger. It's quite a way away from delivering that goal though, I was really just experimenting and playing with PropertyDrawers.

    By the way, something in the LuaInterface documentation caught my eye - it does have a partial mechanism for creating new CLR types. So in principle maybe you can create new MonoBehaviours. I haven't investigated fully though, and as I said before, I doubt this would work on AOT platforms.
     
  8. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    Wow, I downloaded the project and it so Awesome.

    Great Demo of how to hook up events and run Lua code. This is exactly to the point. Definitely should be included as part of your Online Unity Demo.
    This demo is simple and clearly demonstrates how Events could be hooked up with Lua. Very much helped me to better understand how Lua and Unity can be used in a practical way. Many Thanks again George.

    "By the way, something in the LuaInterface documentation caught my eye - it does have a partial mechanism for creating new CLR types. So in principle maybe you can create new MonoBehaviours."

    This is very interesting indeed. I was on the Xamarin site and they noted that Reflection.Emit is not allowed but most of the other Reflection calls are valid on AOT. Would this be the case that LuaInterface is using Reflection.Emit?

    Edit: Found in GenerateEventAssembly.cs
    using System.Reflection.Emit;

    Is this the file that generates new CLR types that you were refering to?

    Cheers.
     
    Last edited: Feb 13, 2014
  9. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    No problem, I'm glad it helped.

    Yes, I think that is the file.
     
  10. HenryT

    HenryT

    Joined:
    Jan 12, 2014
    Posts:
    6
    I'm recently evaluating lua bind solution for Unity3D.
    KopiLuaInterface seems to be the most amazing one among all.
    KopiLuaInterface is really easy to use and works on iOS and Android devices.
    It's an awesome work gfoot ! :D

    I did some test to ensure KLI can suit for further development of our project. But got this problem.

    Problem Detailed
    As to the Debug.Log() call, I need to put the following line in lua script

    Code (csharp):
    1.  
    2. UnityEngine = luanet.UnityEngine
    3. Debug = UnityEngine.Debug
    4.  
    5. function print()
    6.     Debug.Log("called by lua")
    7. end
    8.  
    But say I want to call a static function in a custom class - MyClass.MyStaticFunc()
    (MyClass is in default namespace)
    Code (csharp):
    1.  
    2. MyNameSpace = luanet.Assembly-CSharp       -- line: 01
    3. MyClass = MyNameSpace.MyClass                 -- line: 02
    4. function foo()
    5.     MyClass.MyStaticFunc()                             -- line: 03
    6. end
    7.  
    The case is if I don't put line 01 and 02 in lua script, error occur on line 02.
    If I put line 01 in lua, error occur on line 02 because of the "-" character.


    Static function call is a common need for scripting.
    If I am doing right, I have two solutions in mind.

    Solution 1:
    Wrap up all custom static function needed into a helper class instance, and send the helper instance to lua

    Solution 2:
    Change default assembly name from Assembly-CSharp to AssemblyCSharp. But I don't know if it's supported by Unity3D. So I will post an ask thread somewhere else.
     
  11. HenryT

    HenryT

    Joined:
    Jan 12, 2014
    Posts:
    6
    I just find a really good solution.

    Code (csharp):
    1.  
    2. luanet.load_assembly("Assembly-CSharp")
    3. MyClass = luanet.MyClass
    4.  
    And everything works like a charm
     
  12. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Yes, you can do that. LuaInterface provides a lot of index functions that mean there are many ways to say the same thing. It is flexible but it can make this stuff quite confusing.

    The lowest level I'm aware of is luanet.load_assembly("Assembly-CSharp") and afterwards luanet.import_type("MyClass") - with namespace if it has one.

    Code (csharp):
    1.  
    2. assembly = luanet.load_assembly("Assembly-CSharp")
    3. MyClass = luanet.import_type("MyClass") -- I think this is the syntax
    4.  
    LuaInterface also provides an indexer on the assembly, so you can pull types out of it directly:

    Code (csharp):
    1.  
    2. assembly = luanet.load_assembly("Assembly-CSharp")
    3. MyClass = assembly.MyClass -- or just keep using 'assembly' explicitly
    4.  
    On top of that, luanet provides an index function on itself that allows you to load types or assemblies as if they were members of luanet. You have to load the assembly first. So I'd expect these to work too, even mixed up with the above:

    Code (csharp):
    1.  
    2. assembly = luanet["Assembly-CSharp"]  -- use square brackets and a string if your name contains odd characters
    3. MyClass = luanet.MyClass
    4.  
    5. -- or just:
    6. MyClass = luanet["Assembly-CSharp"].MyClass
    7.  
    Recent versions of LuaInterface also provide an 'import' function which lets you import an assembly's contents into the global namespace. It doesn't actually create global symbols, it just adds an index function to the global metatable that looks things up in imported assemblies if they don't match true globals. So you can do this too:

    Code (csharp):
    1.  
    2. import "Assembly-CSharp"
    3.  
    Now you can refer to MyClass or any other type defined in the assembly just as you would with the previous examples, but without needing an explicit global for every type in the assembly. However, that last one is not in the version I published for KopiLuaInterface. I might push an upgraded version in the next few days, but I haven't had a chance to test it properly yet.

    In the meantime, if you look at LuaInstance in that zip I linked in another post, you'll see a similar import function that does the same trick.
     
  13. HenryT

    HenryT

    Joined:
    Jan 12, 2014
    Posts:
    6
    Thanks gfoot for clarifying that :)

    The only problem I get before setup KLI in our project is debugging.
    I read through the thread and tried as AnomalusUndrdog did.

    Code (csharp):
    1.  
    2. try
    3. {
    4.     lua.DoString(luaStr)
    5. }
    6. catch (KopiLua.Lua.LuaException e)
    7. {
    8.     lua.DoString("err = debug.traceback()")
    9.     string output = lua.GetString("err");
    10.     Debug.Log(output);
    11. }
    12.  
    But the output is always
    Code (csharp):
    1.  
    2. stack traceback:
    3.     [string "chunk"]:1: in main chunk
    4.  
    No matter which line exactly the error lays.

    So how can I achieve the goal?
     
  14. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,551
    I'd hazard to say perhaps we'd have to edit the code in LuaInterface for that... something like, for that code fragment, counting the number of newline characters up to the part that generated the error could be used for indicating the line number perhaps?
     
  15. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Each string you pass to Lua is evaluated as its own "file", and line numbers within each string start at 1. It should increase the line numbers if you use newline characters in the string though, just like with files.

    The underlying VM functions that parse and execute the string do support naming the string, in the same way that chunks that came from files get tagged with the filename. LuaInterface's DoString function doesn't support that though, it just tells the Lua VM that the chunk is called "chunk", and that's what Lua's debug functions are telling you the string was called. This happens on line 224 of Lua.cs in LuaInterface - you could add an optional argument to DoString and pass that through instead of "chunk" if it is specified.

    Really though DoString is usually not the best way to interact with the VM. Using files is more traditional. It is a bit tricky from Unity if you want it to work in all configurations. I added a virtual filesystem to KopiLua which lets you intercept file access and redirect it - I've mostly been using a redirector that maps Lua filesystem access to Unity's Resource system. This works pretty well. You could do something similar for fetching files from a web server, or loading them from any local archive you want.

    Also regarding debugging, check out my earlier post about my KopiLuaDebug repo. It was a mostly-successful effort to connect visual remote debugging to KopiLua, using the ZeroBrane IDE.
     
  16. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Regarding this code:

    Code (csharp):
    1.  
    2.     lua.DoString("err = debug.traceback()")
    3.     string output = lua.GetString("err");
    4.     Debug.Log(output);
    5.  
    I thought I could explain some alternatives you might prefer...

    DoString returns an object[] containing whatever is on the stack, so you can write this instead and avoid polluting the Lua global namespace:

    Code (csharp):
    1.  
    2.     object[] returnValues = lua.DoString("return debug.traceback()")
    3.     Debug.Log(returnValues[0]);
    4.  
    You can also bypass DoString here completely - something like this should work too:

    Code (csharp):
    1.  
    2.     object[] returnValues = lua["debug.traceback"].Call();
    3.     Debug.Log(returnValues[0]);
    4.  
    This saves the bother of compiling your Lua string just for the sake of calling one function.

    That's safe in my version of LuaInterface. In the upstream version it leaks memory in the VM, as you need to dispose the function you got back from lua[...], like this:

    Code (csharp):
    1.  
    2.     var traceback = lua["debug.traceback"];
    3.     object[] returnValues = traceback.Call();
    4.     traceback.Dispose();
    5.     Debug.Log(returnValues[0]);
    6.  
     
  17. HenryT

    HenryT

    Joined:
    Jan 12, 2014
    Posts:
    6
    Thanks again gfoot and AnomalusUndrdog !

    Buddy in our team has enabled printing error line in a trunk, with small tweaks in LuaInterface code.

    I will check the code and post the solution when get time.

    Our purpose was packing lua into assetbundle, sadly iOS doesn't allow downloading assetbundle at all.
     
  18. Kaboom

    Kaboom

    Joined:
    Mar 16, 2014
    Posts:
    32
    Is it possible to call/use overloaded operators on Unity types? For example, scaling a Vector3:

    Code (csharp):
    1. v = UnityEngine.Vector3(x, y, z) * 3
    This results in an error: "LuaInterface.LuaException: [string "chunk"]:4: attempt to perform arithmetic on a userdata value".

    Is there any way to refer to Vector3's operator*? Or is it necessary to reimplement the operations in Lua?
     
  19. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I don't know for sure but I'll post my first guess and some caveats.

    luanet has a method called get_method_bysig that allows you to access pretty much any C# method, one way or another. You specify the object (or class for statics), method name, and argument types, and it returns a Lua callable referring to the method. So you could do this ugliness:

    Code (csharp):
    1.  
    2. vecMulFloat = luanet.get_method_bysig("UnityEngine.Vector3", "operator*", "UnityEngine.Vector3", "float")
    3. newvec = vecMulFloat(vec, 5)
    4.  
    So get_method_bysig here returns a Lua callable that chains to Vector3.operator*(Vector3, float).

    You might need "System.Single" or similar instead of "float", and I'm also not sure whether "operator*" is the correct name for the operator - this lookup happens at the CLI level I think, so you probably need the CLI names for the types and method names, which aren't necessarily the same as the C# names.

    You might also need to pass the type object rather than the type name as the first argument, I don't remember exactly. The parameter names are definitely passed as strings though. Try these kinds of things for the first argument if the string isn't working:

    Code (csharp):
    1.  
    2. UnityEngine.Vector3
    3. luanet.UnityEngine.Vector3
    4. luanet.import_type("Vector3")
    5. luanet.import_type("UnityEngine.Vector3")
    6.  
    LuaInterface has so many subtly different ways to refer to types, I never remember which ones work best, though I think import_type is generally the sledgehammer that resolves most stubborn problems.

    As for getting the overloaded operator to work in Lua without using an explicit function call, I'm not sure that's practical. I think for Lua tables you'd normally need to set up an entry in the object's metatable, called '__mul' or something like that. I think you can't do that for light userdata, which I believe is what LuaInterface uses to expose C# types.
     
    Last edited: Mar 17, 2014
  20. Kaboom

    Kaboom

    Joined:
    Mar 16, 2014
    Posts:
    32
    Hi George, thanks for the quick and thorough reply! I'll see what I can cook up :)
     
  21. HenryT

    HenryT

    Joined:
    Jan 12, 2014
    Posts:
    6
    Hey guys! In my last post I get the problem of failing of output error line.

    Code (csharp):
    1.  
    2. stack traceback:
    3.     [string "chunk"]:1: in main chunk
    4.  
    Here is the solution.

    Find the following line in idebug.cs in luainterface souce code. Around line 613
    Code (csharp):
    1.  
    2. luaO_pushfstring(:, "%s:%d: %s", buff, line, msg);
    3.  
    Save the "line" value to somewhere you like, a static field eg. Then you can get it.
    I don't know about the reason.
     
  22. Kaboom

    Kaboom

    Joined:
    Mar 16, 2014
    Posts:
    32
    Awesome, I think I've got it - you were almost spot on! You were right, the internal names for the overloaded operators are different. Boo's operator overloading gave me a hint which a little searching confirmed: they're called op_Addition, op_Multiply, etc. internally. Here's a list: http://boo.codehaus.org/Operator+overloading. It is indeed System.Single to refer to float, by the way.

    Then, it is a matter of poking the retrieved method into the type's metatable, which you have to do through an (arbitrary) instance:

    Code (csharp):
    1.  
    2. Add = luanet.get_method_bysig(Vector3, "op_Addition", "UnityEngine.Vector3", "UnityEngine.Vector3")
    3. getmetatable(Vector3.zero).__add = Add
    4.  
    5. c = Add(Vector3(1, 2, 3), Vector3(3, 2, 1))
    6. print("Method Add:", c.x, c.y, c.z)
    7.  
    8. c = Vector3(1, 2, 3) + Vector3(3, 2, 1)
    9. print("Operator +:", c.x, c.y, c.z)
    10.  
    11. Mul = luanet.get_method_bysig(Vector3, "op_Multiply", "UnityEngine.Vector3", "System.Single")
    12. getmetatable(Vector3.zero).__mul = Mul
    13.  
    14. c = Mul(Vector3(1, 2, 3), 3)
    15. print("Method Mul:", c.x, c.y, c.z)
    16.  
    17. c = Vector3(1, 2, 3) * 3
    18. print("Operator *:", c.x, c.y, c.z)
    From here, it's just a matter of a nested "for type in types, for operator in operators, peek/poke" loop to get Vector2, Vector3, and other useful types (Quaternion?) working with a nice spoonful of syntactic sugar. Caveat: the reverse operations don't work (3 * Vector3.one instead of Vector3.one * 3).
     
    Last edited: Mar 19, 2014
  23. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    @Kaboom,

    "From here, it's just a matter of a nested "for type in types, for operator in operators, peek/poke" loop to get Vector2, Vector3, and other useful types (Quaternion?) working with a nice spoonful of syntactic sugar. Caveat: the reverse operations don't work (3 * Vector3.one instead of Vector3.one * 3)."

    This operator stuff is really cool. Could you post some more on the nested types, operators in operators, etc.. that you are coming up with. This would be a great Lua/Unity utility library.

    Cheers..
     
  24. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Oh cool, I wasn't sure that you'd be able to poke these things into the C# objects' metatables, but it's great if you can.

    It ought to be possible for LuaInterface to automatically do this, it's a shame that it doesn't.
     
  25. Kaboom

    Kaboom

    Joined:
    Mar 16, 2014
    Posts:
    32
    Not so much "library" and more "10 minute hack", but something like this works pretty well for basic Vector math:

    Code (csharp):
    1.  
    2. function print(...)
    3.     UnityEngine.Debug.Log(table.concat(arg, " "))
    4. end
    5.  
    6. types = {
    7.     "UnityEngine.Vector2",
    8.     "UnityEngine.Vector3",
    9.     "UnityEngine.Vector4",
    10. }
    11.  
    12. ops = {
    13.     { "op_Addition",    "__add", "(self)", "(self)" },
    14.     { "op_Subtraction", "__sub", "(self)", "(self)" },
    15.     { "op_Multiply",    "__mul", "(self)", "System.Single" },
    16.     { "op_Division",    "__div", "(self)", "System.Single" },
    17. }
    18.  
    19. for i, typename in ipairs(types) do
    20.     for j, op in ipairs(ops) do
    21.         name, slot, arg1, arg2 = unpack(op)
    22.         if arg1 == "(self)" then
    23.             arg1 = typename
    24.         end
    25.         if arg2 == "(self)" then
    26.             arg2 = typename
    27.         end
    28.         type = luanet.import_type(typename)
    29.         method = luanet.get_method_bysig(type, name, arg1, arg2)
    30.         getmetatable(type.zero)[slot] = method
    31.     end
    32. end
    33.  
    34. Vector2 = UnityEngine.Vector2
    35. Vector3 = UnityEngine.Vector3
    36. Vector4 = UnityEngine.Vector4
    37.  
    38. v = Vector2(1, 2) + Vector2(2, 1)
    39. print("Operator +:", v:ToString())
    40.  
    41. v = Vector3(4, 3, 2) - Vector3(1, 1, 1)
    42. print("Operator -:", v:ToString())
    43.  
    44. v = Vector4(1, 2, 3, 4) * 3
    45. print("Operator *:", v:ToString())
    46.  
    47.  
     
  26. Maybe_memory

    Maybe_memory

    Joined:
    Sep 15, 2012
    Posts:
    8
    Hello, KopiLua relly did a good job.
    So did u get a link.xml which can use on ios with 'strip bytecode' op level now?
    And I also want to ask u what editor did u use to develop?
    I need an editor that can auto-complete the code.
    Or what can I do to use zeroBranStudio to do this?
    Thank u very much.
     
  27. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I use a plugin for KopiLua that redirects file access via Unity's Resources system, so I can place foo.lua.txt in a Resources folder and as far as Lua is concerned, that file is "foo.lua". Unfortunately Unity requires the ".txt" extension as well, which confuses things like ZeroBrane, though that's not ZB's fault.

    You can see an example of this, including the file access redirection plugin, in the KopiLuaDebug project I linked to earlier: https://github.com/gfoot/kopiluadebug

    To make that process smoother, you can use an AssetPostProcessor in Unity that spots changes to .lua files in your Assets folder and makes copies in the Resources folder with the extra ".txt" extension. Then the runtime is still working based on the .lua.txt files, but ZB edits (and debugs) the plain .lua files, and everybody is happy.
     
  28. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    Try this:
    Code (csharp):
    1.  
    2. <linker>
    3.     <assembly fullname="KopiLua">
    4.         <namespace fullname="KopiLua" preserve="all"/>
    5.     </assembly>
    6.      
    7.     <assembly fullname="KopiLuaDll">
    8.         <namespace fullname="KopiLuaDll" preserve="all"/>
    9.     </assembly>
    10.      
    11.     <assembly fullname="KopiLuaInterface">
    12.         <namespace fullname="LuaInterface" preserve="all"/>
    13.     </assembly>
    14. </linker>
     
  29. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,459
    @Kaboom, Thanks for the example.

    @ TonyLi, Thanks for the link.xml
     
  30. Maybe_memory

    Maybe_memory

    Joined:
    Sep 15, 2012
    Posts:
    8
    Hello, I'm doubting that did anyone use ZeroBrane Studio to develop with unity on Mac?
    And how do u handle the auto-complete?
    Did anyone got an unity.lua like love2d.lua that can auto-complete while developing?
    Thanks.
     
  31. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I have tested using ZeroBrane with KopiLuaDebug on Mac in the past, and I think it worked fine, I don't recall any problems.

    I don't know anything about auto-completion in ZeroBrane, but I might investigate sometime. I was planning to make a package that sits on top of KopiLuaInterface and makes the integration with Unity a bit more direct, but haven't had any time to work on it recently.
     
  32. PabloJMartinez

    PabloJMartinez

    Joined:
    Feb 7, 2013
    Posts:
    21
    Good job, I'll look into this.
     
  33. TylerPerry

    TylerPerry

    Joined:
    May 29, 2011
    Posts:
    5,577
    Hi I've been looking into this and I'm wondering if anyone has any advice on disabling "luanet" I don't want users to be able to access everything, just some stuff I want to define. an easy way would be to remove "luanet" from the string but its not that good, any ideas on how to do that?
     
  34. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    To begin with, you can just not use LuaInterface at all - you can just use plain KopiLua. Then you need to work a bit harder defining explicit entry points into your code from Lua.

    If you continue to use LuaInterface, you can unset the "luanet" global variable if you want to, which removes the usual APIs. You could do that after you've imported whatever you'd like the user to have access to. I think you need to be careful though because if you give access to something like UnityEngine then the user can basically instantiate any class they like from there.

    Also, if you keep a private reference to luanet in a module or something, be aware that the user can probably still dig it out later on if they're determined. I believe the best way to be really safe is to just not use magic like LuaInterface, and define an explicit API instead which is small enough for you to be confident about. This is what I've started doing myself.
     
  35. TylerPerry

    TylerPerry

    Joined:
    May 29, 2011
    Posts:
    5,577
    Sorry for being a nuisance but could you give any information on how to do that? I'm not sure if I'd have to do that in KopiLuaInterface.DLL or if I do that in my code. ATM I'm just doing a test with this:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using LuaInterface;
    5.  
    6. public class LUATest : MonoBehaviour
    7. {
    8.     public TextAsset code;
    9.  
    10.     void Start ()
    11.     {
    12.         Lua luaInstance = new Lua();
    13.         luaInstance.DoString(code.text);
    14.     }
    15. }
    16.  
    Inside "code" is this lua code:

    Code (csharp):
    1.  
    2. UnityEngine = luanet.UnityEngine
    3. System = luanet.System
    4.  
    5. UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube)
    6.  

    I searched through LuaInterface and LuaDLL source to try and find something but what I found I wasn't sure on in LuaInterface theres a few lines similar to this:

    Code (csharp):
    1.  
    2. LuaDLL.lua_setglobal(luaState, "luanet");
    3.  
    I'm not sure if I should just remove that? And also if I remove that then how can I add a namespace or something for my lua code to access?(AFAIK there's no documentation so I'm just guessing here)

    Thanks :)
     
  36. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    You can either do this in Lua:

    Code (csharp):
    1.  
    2.     luanet = nil
    3.  
    or this in C#:

    Code (csharp):
    1.  
    2.     lua["luanet"] = null;
    3.  
    Either way should clear the global luanet variable, so that later Lua statements won't be able to access it.

    You can also remove the line you found in the LuaInterface source, but then you won't be able to use luanet at all.
     
  37. TylerPerry

    TylerPerry

    Joined:
    May 29, 2011
    Posts:
    5,577
    Sweet thanks :)
     
  38. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    George,

    Is there by any chance a build for Windows Phone 8 (WP8 )? WP8 uses pared-down assemblies that don't include System.Reflection.Emit or System.Diagnostics.Process.
     
    Last edited: May 14, 2014
  39. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Hi Tony

    I'll check this out and get back to you. My gut feeling is that removing dependence on System.Diagnostics.Process should be simple, but System.Reflection.Emit is harder. It's only used by the high level LuaInterface layer, not by KopiLua itself, and it's not needed most of the time. On iOS for example it works fine so long as you don't do things that require "Emit". But if WP8 doesn't provide the function at all, so that your game won't build without it, then we would need a separate DLL for WP8 that doesn't reference it - or maybe a stub DLL that provides a fake System.Reflection.Emit just to keep the linker happy.

    I haven't looked at exactly what you're using Lua for - it would help to know whether your code requires LuaInterface or whether it can work with just the lower level KopiLua. LuaInterface provides glue to make it easier for you to expose objects from C# to Lua, and to allow Lua scripts to initiate that process themselves, i.e. access assemblies, use C# types, call methods, create objects. Some LuaInterface features can't work without Reflection.Emit, but you can usually work around them.
     
  40. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    Thanks, George! I've been using LuaInterface, but everything's isolated in a wrapper class so it shouldn't be too hard to switch to lower-level KopiLua calls instead if necessary. If I get a chance to build and test a stub DLL, I'll post here.
     
  41. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I had a look at this, but although any fixes are probably really simple, getting in a position to actually build Windows Store or Windows Phone apps is beyond what I can do in my free time at the moment - it requires a Windows 8 PC with Unity, Visual Studio, and a bunch of SDKs installed. I have limited access to a Windows 8 PC, but not the time required to download all this software on it, apply for a Windows Store developer license, etc.

    I have a horrible vision that one day Google will follow suit and start requiring Android developers to use Chromebooks while wearing Google Glass, then the whole mobile development world can finally implode.
     
  42. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    Interesting timing! Just yesterday I set up a Windows 8 PC with Unity, Visual Studio, and the SDKs. I'll set up a developer license and look into this.
     
  43. JaredThomson

    JaredThomson

    Joined:
    Nov 15, 2013
    Posts:
    16
    Hey man, just wanted to give you a shout. This is really great and I'm super happy you made it. Keep up the great work!
     
  44. Maybe_memory

    Maybe_memory

    Joined:
    Sep 15, 2012
    Posts:
    8
  45. Maybe_memory

    Maybe_memory

    Joined:
    Sep 15, 2012
    Posts:
    8
    it works after I changed line 155
    return (base.load("return " .. tostring(s):gsub("\\/", "/")))()
    to
    return (base.loadstring("return " .. tostring(s):gsub("\\/", "/")))()
    : )
     
    Last edited: Jun 22, 2014
  46. nia1701

    nia1701

    Joined:
    Jun 8, 2012
    Posts:
    74
    Hi Everyone, sorry if I should do more reading and this is not something you are supposed to do but I'm wondering this:

    How do you access a variable directly from a lua script?

    Say I have a static class: Variables
    Then I have a method
    static bool Variables.GetBoolVar(string id);
    I thought from what I read above that I could use:
    lunanet.AssemblyCSharp.Variables.GetBoolVar("id"), but this seems to do nothing.

    Any leads?

    Thanks so much!
     
  47. nia1701

    nia1701

    Joined:
    Jun 8, 2012
    Posts:
    74
    Well I kind of got what I was going for....just writing a wrapper of sorts.
    I can access methods on the object if I pass the object first to the luascript like:
    Lua _lua;
    void Start()
    {
    _lua = new Lua();
    _lua["thisObj"] = this;
    }

    public string GetString()
    {
    return SomeClass.SomeString;
    }

    then in the lua I would have:
    testString = thisObj:GetString()

    Thanks!
     
  48. jkraptor

    jkraptor

    Joined:
    Sep 28, 2013
    Posts:
    24
  49. nia1701

    nia1701

    Joined:
    Jun 8, 2012
    Posts:
    74
    Hi @jkraptor , I haven't experienced that issue. Maybe you need to first declare the string variable with a blank string. Its possible lua can't determine that Name() is supposed to be a string?
     
  50. Siney

    Siney

    Joined:
    Dec 22, 2014
    Posts:
    5
    you can use slua https://github.com/pangweiwei/slua, fastest lua binding for unity3d, 10x-100x faster than ulua /kopiLuaInterface

    static code generating, no reflection, no extra gc alloc, very fast

    above 90% UnityEngine interface exported ( remove flash, platform dependented interface )

    100% UnityEngine.UI interface ( require Unity4.6+ )

    support UnityEvent/UnityAction for event callback via lua function

    support delegate via lua function

    support custom class exported

    export enum as integer

    return array as lua table

    using raw lua 5.3, can be replaced with luajit/lua5.1.
     
    hima likes this.