Jump to content
  • Advertisement
Sign in to follow this  
wcassella

Unity Integrating a scripting language

This topic is 1125 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

I'd like to integrate a scripting language into my game, and at the moment I've narrowed it down to either Lua or Angelscript. Here's a rundown of the features I like and dislike about each:

 

+ = pro

- = con

? = unsure

 

Lua:

+ Easy to integrate

+ Strong community

+ Plenty of tools (Decoda, syntax highlighting in a great number of text editors, etc)

? Syntax (never been a huge fan of dynamic typing, and my first language was Python. It may have its uses here though)

 

Angelscript:

++ Even easier to integrate

+ Decent community (not as strong as Lua's though)

+ Syntax (static typing, closer to what I'm used to)

- Preprocessor (see below)

? Performance (benchmarks indicate it's generally slower than Lua, but I'm not sure if this will actually be a problem)

 

One issue (?) that exists among all the scripting languages I've looked at is memory management. At the moment all of my C++ code is either using unique or weak ownership (via my own UniquePtr and WeakPtr classes). Neither scripting language really has any concept of that, and while I suppose I could dance around the issue by simply not exposing anything that requires "ownership" to the scripting layer, that could get very tricky. While it wouldn't be much of an issue creating objects on the scripting side, sharing objects created in C++ would be difficult.

 

I guess it really comes down to what role scripts are going to play in my workflow. At the moment all I'm planning on using them for is really simple level-based scripting (player enters code x into keypad, door opens and monster spawns), with the real meat of the game written in C++. The simplicity of Lua would lend itself very well to this; and in fact dynamic typing would be an advantage here, since as long as the overall interface remains the same, types can change however you want on the C++ side without updating scripts. However, it would be ideal to leave the capability of scripts as wide as possible; such as defining and extending entire classes, rather than just simple event handling.

 

Speaking of which there seems to be at least some support for extending C++ classes in both languages, though it may require some hacking. I'm not sure which language would be better for this though.

 

On another note, Angelscript's support for sharing code between modules appears to be a bit limited (basically requiring a preprocessor). I may be misunderstanding this, but if that's the case then that's very disappointing. Header files + the preprocessor are my least favorite "features" of C++ (though admittedly macros can be very handy if they are used correctly).

 

I've also considered the possibility of creating my own scripting language. While that would be a fun project, I've been treading water long enough on this one so I'd rather just integrate an existing language or none at all. Seeing as Angelscript has been in development for about 10 years and Lua for much longer, I highly doubt I could create a decent alternative in any reasonable amount of time anyway.

 

You guys probably have a lot more experience with these issues than I do, so I'd love to hear your thoughts.

Edited by Salty Boyscouts

Share this post


Link to post
Share on other sites
Advertisement
weak ownership ...
Neither scripting language really has any concept of that

Lua has weak tables. You can treat such table as rough equivalent to weak pointer.

E.g.

local object = {
    name = "blah-blah-bla",
    health = 100
}

local weak_table = setmetatable({}, {__mode="v"})

-- store object
weak_table.link = object

-- lose object
object = nil

-- depending on GC activity, 'link' field is either still alive,
-- or already missing from 'weak_table'
print(weak_table.link)

-- force GC cycle, see that 'link' now lost
collectgarbage()
print(weak_table.link)
Edited by vstrakh

Share this post


Link to post
Share on other sites

Base it on your preferences. I tried already lua and prefer it. Angel script may be a bit easier to debug while lua has real coroutines and I think is faster (especially last lua release).
There are out there lua editors for sure, don't know about angel script.)

also consider dependencies, if you want to use lua, you want for sure to use also an additional C++ framework to automate most binding tasks, while angelscript have that feature natively

 

also note that based on my experience Angel script is not a full fledged OO language so if you are used to stress limits of the languages you use (in example you go heavily with templates and reflection in C# and metaprogramming in C++) then probably you will find better with lua because thanks to its "dynamicity" allow to overcome the limits of the language. Said that, you have to try both.

I think I'll try Angelscript now, I just saw it has Cmake script => easy compilation rolleyes.gif

Edited by DemonDar

Share this post


Link to post
Share on other sites

If they both support weak references, is there anyway to make that the default? If that were the case then the C++ code could be treated as the owner for any objects that have to be passed between the languages (such as GameObjects, etc), and all script-side references could be treated as null once the object is destroyed.

 

A simpler solution may just be to use shared pointers for everything (and consider any object passed into the scripting layer as having an additional shared pointer until it's cleared by the garbage collector), however there are several benefits to purely Unique/Weak ownership even beyond memory management, and I'm not quite ready to give those up.

Share this post


Link to post
Share on other sites


One issue (?) that exists among all the scripting languages I've looked at is memory management. At the moment all of my C++ code is either using unique or weak ownership (via my own UniquePtr and WeakPtr classes). Neither scripting language really has any concept of that, and while I suppose I could dance around the issue by simply not exposing anything that requires "ownership" to the scripting layer, that could get very tricky. While it wouldn't be much of an issue creating objects on the scripting side, sharing objects created in C++ would be difficult.

I wouldn't allow any sort of shared script/native representations of objects in the first place, which allows you to avoid these sorts of cross-domain ownership issues. At which point it doesn't matter how they each handle object ownership/lifetime, so long as you can properly marshall between the two.

Share this post


Link to post
Share on other sites

Neither scripting language really has any concept of that

That's about right, since it would require some horrible indirection/registration of weak references, and GCs could easily lead to the objects being destroyed at a bad time. One frame, the object works, the next - it's broken. Hard to debug. Lua works around the registration issue with weak tables though, as mentioned above. The GC issue still remains, though.
 
What I've found to work for me (even though I use my own scripting language, SGScript, the concept should still apply to others) is weak objects: make scripting object handles themselves weak.
 
Every object has interface/data pointers or some equivalent of that: interface defines how the language should deal with it, the data pointer allows linking C++ data to use in bindings.
When C++ code decides to drop an object, the C++ part of it is destroyed and the scripting object receives new interface/data pointers (empty interface definition + NULL data), thus unlinking it from its contents. Any access will fail with a descriptive error.
 
Another option is to refer to objects through named handles only (like "find('player').check_something()"). Should work everywhere but it'll increase code size.
 

I've also considered the possibility of creating my own scripting language. While that would be a fun project, I've been treading water long enough on this one so I'd rather just integrate an existing language or none at all. Seeing as Angelscript has been in development for about 10 years and Lua for much longer, I highly doubt I could create a decent alternative in any reasonable amount of time anyway.

I'm 3-4 years in so I completely agree that it's no small task to create a fully featured scripting language. The payoff is impressive, though there will still be lots of regrets and certain features just out of reach (like low-cost loops, JIT and smart optimizations).
 
However, creating a basic "command list" style language or defining a basic language like what ant (the build tool) has in XML (or any more acceptable alternative) is quite simple, actually. Judging by your usage description, it may just fit your needs, though expect at least a week of work to get something to run and at least a month of work to fit all your needs (if they're indeed simple).

Edited by snake5

Share this post


Link to post
Share on other sites


If they both support weak references, is there anyway to make that the default?

All references within weak tables is weak references. You don't have to create separate weak table for every weak reference.

Typically you have something like "cache", single table where you store related items in the way, that will not prevent GC from collecting objects when there's no strong references left.

 


If that were the case then the C++ code could be treated as the owner for any objects that have to be passed between the languages (such as GameObjects, etc), and all script-side references could be treated as null once the object is destroyed.

Actually, it's much easier is to make all shared objects as owned by scripting VM.

C++ might create strong references (stored in scripting vm) when it wants to "own" object.

Share this post


Link to post
Share on other sites

Start by thinking of the scripting VM as its own independent domain, with absolutely no concept of shared state or direct access with your native code. We could even assume it's in a separate process entirely.

 

Notice how this resembles a client/server architecture. As such, you could use RPC mechanisms to allow them to communicate. Notice how all the mechanics and details of the script/native interaction are now the responsibility of a dedicated communication layer, as opposed to requiring the script code or native code to understand those details at every turn. Shared ownership isn't even a thing.

 

Next, let's move the script VM to the same domain as the native code and allow them direct access to each other. You no longer need to marshall and communicate a copy of the data across a domain boundary and have it updated remotely; you just set the new value directly and raise a 'changed' event. The state update can be accomplished via injection -- the script owns the data it's going to consume, but passes a reference to native code so it can be populated as necessary. Before the script goes away, it passes a null reference to the native code indicating it's no longer valid. Since we've designed the architecture so that the scope of the script's ownership always encapsulates the scope of the native code's ownership (or vice versa) of a particular piece of state, we don't run into any of the typical shared ownership issues and we could use a weak reference if the scripting language supports it; but at that point it's an implementation detail.

 

However the cost of such an approach is requiring the native code to have privileged knowledge of the script's data layout, since you're no longer using the same neutral data representations which exist as part of a communication protocol. You trade run-time efficiency, for additional maintenance overhead. However I've often found that to be an acceptable trade-off , since the script-side interaction with an RPC layer can often be a problematic if lots of short-lived temporary objects end up being created often.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!