Jump to content

  • Log In with Google      Sign In   
  • Create Account

SGScript - the new and improved scripting engine


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
2 replies to this topic

#1 snake5   Members   -  Reputation: 225

Like
2Likes
Like

Posted 11 July 2014 - 02:49 AM

logo-red.png
 
The Story
 
Just about as long as I've done game programming, I remember interacting with some kind of a scripting engine. GML, Lua, AngelScript, Python. All of them have something to dislike, something that makes a developer pull his hair in an attempt to defy laws of gravity as even that seems easier than making the code behave just the way it's needed at the time. I'd been that developer for some time and I've had my share of those moments. Then, two years ago, near the beginning of the year 2012, I decided that I should try to address every problem I noticed in there, as well as integrate the successful decisions of various languages. There were tradeoffs to be made, not all good things go well together, though there is some place for being proud of what's accomplished. High portability, ease of integration, accessible API and debugging / profiling tools.
 
The Reasons and Solutions

  • Programmability - control over software should not be exclusive to the man with the compiler and all that other stuff. Sometimes it helps to be able to just change the things you want. In those moments, SGScript is there for you. As a dynamic language with a friendly interface, it allows to do a great deal of work with a few small scripts.
  • Portability - with other operating systems and cloud storage becoming more accessible, it is important that binaries as well as SDKs are small, and everything works largely the same way everywhere, with only a few things to swap when moving between different OS's, to make it easy to work on your projects anywhere, without setting up huge SDKs and build systems. Working in a cloud storage folder is a real possibility, and not only that - I've been doing it when I need to test how things work on different platforms.
  • Accessibility - it should be easy to pick up the language. SGScript syntax is mostly based on C / JavaScript. This saves time for most common users of scripting languages in that they know one or two similar languages and the syntactical differences can be picked up in a day. Behaviors are documented and simple.
  • Compatibility - with a few code files, everything's possible. Adding non-trivial makefiles, various dependencies on other libraries or even a C++-only API makes things worse. It's sometimes necessary or helpful but certainly not here. SGScript therefore can be fully compiled with just one step, using the most available tools: GCC, a C runtime library and GNU Make.
  • Performance - don't you just *love* it that when closing in on the release date, suddenly there's garbage collection hiccups everywhere and there's no good way of getting rid of them? Since memory management to some extent is always a necessity, it's easier to just start with that. There's not much to be done anyway and whatever there is, the included memory profiler will help with that. It shows allocations / frees / allocations - frees (memory block count change) / memory usage change in bytes per call stack frame so it's easy to see where your resources go and where they come back.

The Package
 
SGScript is the game scripting solution and a library that helps you add external programmability to your software. To find out more, you can visit the website at http://www.sgscript.org! You can even try the language at http://www.sgscript.org/try to see for yourself how easy it is to use.
 
The Extensions
 
I've built a few extension libraries for SGScript. All of those can be found at https://github.com/snake5?tab=repositories. sgs-sdl, sgs-box2d, sgs-audio and sgs-ui are some of the more finished ones, though they do lack proper documentation at the moment.
 
SGScript in the Wild
 
I've used these libraries for two published game demos. Both are top-down shooters due to their artistic simplicity.
Ludum Dare #29 game: http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&uid=34947 (includes source code). Using pre-v0.9.5 libraries so swapping something might not work or require the full set of new libraries + some code changes.
TACStrike: http://sgscript.org/files/tacstrike.zip (screenshots: LBrsYGds.jpgv0ohEnEs.jpguPU7Lj7s.jpg). Source code might be released later. Using old (pre-v0.9.0) libraries.
 
Near Future
 
Currently the plan is to finish a UI toolkit, make a basic 2D game engine and an editor, finish other libraries and document all written code to make them available for everyone. As demonstrated, all those libraries are usable and stable, however the lack of documentation leaves only sample code and original source code as the only ways to learn the library.
 
UI library test video: http://screencast.com/t/yPZ7nV3zYKL
 
UI library / 2D editor screenshots: GhJdZyps.png | 1tpEsGus.png
 
sgs-sdl-3D screenshots: ox40MOKs.png | auHMPSgs.png | zbhoaZ0s.png
 
Conclusion
 
I hope you'll have just as much fun using the library as I do. If you have any questions about it, you can post them here or ask me directly. If you run into any bugs, you can either post them in GitHub (https://github.com/snake5/sgscript/issues) or send me an e-mail. A test case, in the form of one or several source files / code snippets, must be included.
 
E-mail: snake5creator+sgscript [at] gmail [dot] com
Twitterhttps://twitter.com/snake5creator


Edited by snake5, 15 July 2014 - 07:56 AM.


Sponsor:

#2 BryanDube   Members   -  Reputation: 136

Like
0Likes
Like

Posted 11 July 2014 - 11:19 AM

Very cool.  I actually have a project I have been working on for some time as well that is remarkably similar.  Rather than my own scripting language I am instead using a C# compliant parser/compiler, but the way we both process the c/c++ files to generate the binding is remarkably similar.  Even down to the GCMark method and macro names, just replace SG_ with NOZ_ and I have the same macros.. crazy. :)

 

It has been a lot of fun developing this stuff actually, hope you enjoyed it as well.



#3 snake5   Members   -  Reputation: 225

Like
0Likes
Like

Posted 16 July 2014 - 08:55 AM

Thanks. The similarities you mentioned are rather interesting. I couldn't find much about your project on the Internet, though.
 

Anyway, the main reason why I'm posting now is this - it seems that every time I ask for opinions (at various online chatrooms), I hear it's not explained why, from a purely objective viewpoint, this engine/language should be used instead of so many others. So I think I'll do that thoroughly right now.
 
Native serialization
[+] SGScript, Python
[-] JavaScript, Lua, Squirrel
 
Without any extra work, most of the data can be converted to a byte buffer so that it could be stored in a file or sent over a network and later converted back again. Languages that don't have it will require extra effort to get it and make sure it works with all kinds of custom objects. How much extra effort? Well, try googling for "lua serialize userdata". I didn't find a single way. SGScript - easy: https://github.com/snake5/sgscript/blob/6e9349a5a1ef5210ee440301b889f9afd78291be/ext/sgsxgmath.c#L248
 
Reference counted memory management support
[+] SGScript, Python, Squirrel
[-] JavaScript, Lua
 
This is a preferred method to garbage collection since it releases resources as soon as possible, avoiding random stalls throughout the game and thus providing a smooth gameplay experience. There are algorithms that reduce these stalls (incremental/generational garbage collection) but, given enough objects, they will be noticeable again. Source: http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/
 
Custom native objects with complex links
[+] SGScript, Python, JavaScript (partial support)
[-] Lua, Squirrel
 
These are objects that can be created in C/C++, with special interfaces that support operator overloading, serialization, debug printing, conversions, cloning, type name and iterator retrieval, index and property retrieval. If not used, this feature has no cost, however it helps greatly with defining fast and accessible interfaces by encapsulating native resource management and access. To see what SGScript objects are all about, check the previous GitHub link, there's quite a lot of them.
 
Native arrays
[+] SGScript, Python, Squirrel, JavaScript (partial support)
[-] Lua
 
Native arrays (not to be confused with arrays that contain native data types, that is a subset of these) offer increased performance and memory-friendly storage over arrays made from hash tables. Array stores size as uint32, capacity as uint32 and values (16 bytes + extended data in SGScript) x size. A table would store all the same + keys (16 bytes + extended data) + hash array (size may differ but it's generally another array with size, capacity and a list of hash and index values). When arrays are considered, less (memory usage) is more (capacity).
 
Map support (all non-string/number keys)
[+] SGScript, Python, JavaScript (requires the support of an extension)
[-] Lua, Squirrel (some types are not supported in both)
 
The ability to map any variable to any other variable provides extended metadata storage possibilities - it can be stored without modifying the original variable.
m = map();
m[ sprite_obj ] = { high = 5 };
 
Game math library
[+] SGScript, Python, Lua, JavaScript
[-] Squirrel
 
A library with vector/matrix objects and functions for games. Not having to rewrite at least the bindings for it saves a lot of time.
 
Native debugging/profiling facilities
[+] SGScript, Python, JavaScript (support differs between JS engines)
[-] Lua, Squirrel
 
Introspective debugging and time/memory usage profiling can help resolve various issues found. SGScript supports call stack time, instruction time and call stack memory usage profilers out-of-the-box. At any point, all data can be dumped via the built-in output facilities that can be rerouted to any file or parser. They are written in C to ensure a practically minimal performance impact while profiling. Significantly less than if the profiler was written in Lua, which is the main solution there.

There's also access to some stats in SGScript so it is easy to see, for example, how many new allocations were done each frame.
 
Advanced native function argument parsing facilities.
[+] SGScript, Python
[-] Lua, Squirrel, JavaScript
 
Every modern scripting engine should have a function that parses and validates function arguments according to a specification and puts the data in the specified locations. With bigger functions it saves you from writing a lot of boilerplate code.
 
SGScript:
SGSFN( "fmt_string_parser" );
if( !sgs_LoadArgs( C, "?m|ii", &off, &bufsize ) ) // in case of type mismatch, emits a warning
    return 0; // ... and returns here to continue execution
 
Lua: (source: http://forums.tigsource.com/index.php?topic=36737.0)
float x  =luaL_checknumber(L,1); // in case of type mismatch, emits a fatal error, cannot continue script execution after this function call
float y  =luaL_checknumber(L,2); // same here
const char* str=luaL_checkstring(L,3); // same here
 
Non-fatal error messaging facilities without exceptions
[+] SGScript
[-] Python, Lua, Squirrel, JavaScript
 
This feature allows you to try and continue execution after a failed function call or intercept the error for debugging with the option of continuing later anyway. This is useful when code is published and there's a necessity to avoid going back to bug fixing immediately, before gathering more information about the state of the program.
 
Why exceptions don't fit the criteria: they force the code to break out of the original execution path, thus severely reducing the usefulness of error suppression with logging.
name = string_cut( other.name ); // warning: missing argument 2; after call, name = null
// name gets printed somewhere as 'null' or is invisible due to some other function not accepting null for a string
// everything else works
 
Built-in introspective pretty-printing (variable dumps)
[+] SGScript, Python, JavaScript
[-] Lua, Squirrel
 
This is a very useful feature to have when you need to debug data (i.e. always). Simply passing a variable to some function (for example, printvar) prints some useful information about it - the type, contents, linked resources.
 
Warning suppression on missing property access
[+] SGScript, Python (requires exception handling code)
[-] Lua, Squirrel, JavaScript (no warnings about it at all)
 
This feature allows to specify, per-read, whether the property is expected to be there or not.
a = obj.prop; // expected, emits a warning if not found
b = @obj.prop; // might not be there, no error
This also works for many other actions, like function calls and assignments.
 
Custom native iterators
[+] SGScript, Python
[-] JavaScript, Lua, Squirrel
 
An extension for custom native objects, it allows to create objects that can be foreach'ed through.
foreach( entry : io_dir( "." ) ) println( entry ); // prints the contents of current directory
 
Dual access dictionaries
[+] SGScript, Lua, JavaScript, Squirrel
[-] Python
 
The ability to access simple dictionaries just like any other object visually and syntactically reduces code complexity.
a.b = x; // simple
a["b"] = x; // not so simple
 
Explicit closures
[+] SGScript
[-] Lua, JavaScript, Squirrel, Python
 
Explicit closures (specifying which local variables to pass over to the newly defined function) make it easier to read code using closures and prevents closure-related accidents, like having a variable changed unexpectedly.
 
Multi-index/property-set operation without temporary tables
[+] SGScript
[-] Lua, JavaScript, Squirrel, Python
 
Simplifying code further without the introduction of sub-optimal memory access patterns.
 
SGScript:
obj.{ // object name written only once, accessed only once
    a = 1, // property write
    b = 2, // property write
    c = 3, // property write
    d = 4, // property write
};
 
Lua, method 1:
obj.a = 1 // property write
obj.b = 2 // property write
obj.c = 3 // property write
obj.d = 4 // property write
// object name written four times, accessed possibly four times (depending on compiler)
 
Lua, method 2:
for k, v in pairs({ a = 1, b = 2, c = 3, d = 4 }) do // create table, property write x4, function call, create closure
    obj[ k ] = v // object access x4, property write x4
end
 
C-like syntax
[+] SGScript, JavaScript, Squirrel
[-] Lua, Python
 
With the overwhelming majority of code being written in C-like languages (http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html), having a compatible syntax helps when you need to copy code - there's simply less changes to perform.
 
Indices start at 0
[+] SGScript, JavaScript, Squirrel, Python
[-] Lua
 
Even though it is argued that it may help someone understand code better (which is actually hard to prove), I have a few arguments to make against it:
  • Array index is generally the distance (or as programmers would rather say, offset) from first element. 1 - 1 = 0. Not a distance from 0th element that doesn't even exist. Not the first element itself because elements have no keys in arrays.
  • Programming languages don't exist in a vacuum. Almost every other programming language treats indices as distances (offsets). Going against the grain makes it hard to interpret both languages at once for comparison or interface design. Whoever has to write that binding, has to keep in mind this difference for every array access made in the binding area. This is brain power not spent well.
  • Similarly to previous argument, this difference makes porting code from other languages harder.

Edited by snake5, 16 July 2014 - 10:59 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS