Scripting in JME3 with Groovy. All about it!

Scripting in JME3 with Groovy. All about it!
Monkeys,

For anyone who still ask for something like “Scripting” with JME3, here is it, about it at once! We nearly reach 3.0, i’m so excited about it and want to write something for it. In this post you will have a good run from Zero to Hero with Groovy and Monkey :stuck_out_tongue: Not kidding!

Quick question: What this related to my other tuts?
Answer: As I wrote the others, I thought I should write this first, because if no one know about Groovy, no one can understand a single line of my code :frowning: , and it’s bad!

Introduction:
We will go from basic setup of Groovy in JMP and then example by example every aspect of game you can develop with Groovy.
More advanced topic come at the end, eg: the way to get the speed of Java, meta-programing, a lot of programming patterns (PP), even AI and Constraint Programming…
Sounds insanse? Nah ah…
[ Let me know if you want to write or to read other topics of Groovy or Scripting. Thanks!]
The wiki link : https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:scripting
Let’s start!

CONTENT
1. GET STARTED
2. LEARN GROOVY
2.1. Syntax and Gotchas
2.2. Meta-programming
2.3. Groovy Builder - SwingBuilder
2.4. Groovy - for smarty
2.5. GPars
3. EMBED GROOVY
3.1. Groovy in JME3
3.2. Groovy in JMP
3.3. Groovy everywhere (snipets)
4. INTO THE GAME
4.1. Basic Scripts
4.2. Event - Trigger Manager
4.3. Configurations with Groovy
4.4. AI Tricks with Groovy
4.5. Build Script with Groovy
5. DESIGN PATTERNS IN GROOVY GAME (WIP)
6. ADVANCED TRICKS
6.1. Hack the JVM with Groovy
6.2. Codegen
6.3. Groovy - Almighty God!

The wiki link : https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:scripting :arrow:

7 Likes

[Moved to Wiki]
Anyone please tell me “How can I delete a reply” ???

1 Like
  1. EMBED GROOVY
    3.1. Groovy in JME3
    3.2. Groovy in JMP
    3.3. Groovy everywhere (snipets)

[Moved to Wiki]

[Moved to Wiki]

[Moved to Wiki]

I like the idea of scripting in groovy. One question: is it possible to execute a script from in-game? For example by putting some code into a some kind of console? I simply mean runtime execution of Groovy code.

@luke1985 said: I like the idea of scripting in groovy. One question: is it possible to execute a script from in-game? For example by putting some code into a some kind of console? I simply mean runtime execution of Groovy code.

Absolutely. Presuming you have some way to get the script, you can just scriptEngine.eval() it.

Also, Groovy actually has a groovy shell that you can pop open with full live groovy edit capabilities, syntax highlighting, etc. I use it in Mythruna when the user runs in “development” mode. They can issue a console command to pop the groovy shell open.

@luke1985 : as far as I understand your description. Yes, you can:

  • Execute a script in game,
  • Change it, excecute again. The editing can be in a simple JME3’s gui text component, or in Swing with code highlight…etc.
  • Command excecution with pre-defined commands
  • Hot reload a Groovy class, including all not-null instances in run-time

About the wiki, it’s not finished. Everything you ask will show up in the wiki page. Thanks

1 Like

your passion for groovy really came out in that wiki page so far, good job :slight_smile: i learnt a lot!

1 Like

Heh. I’d love to go Groovy myself, but I’ve been finding it very hard for me to explore the set of methods that a passed-in object supports.
I’m not sure how people in the dynamic programming camp deal with this; do they simply learn the entire standard libraries by heart, or do they do something simpler?

@toolforger said: Heh. I'd love to go Groovy myself, but I've been finding it very hard for me to explore the set of methods that a passed-in object supports.

This is a downside. Often if I want to know what methods are on a dynamic variable, and I know what that dynamic variable is, I just cast it to that object type.

Related to groovy scripting, I recently went through my scripts and how they are loaded to try and figure out why it was loading so f$*ing slow. I blogged about it here: http://sploreg.com/blog/?p=15

1 Like

@Sploreg: Yeah, nice article!

I’ve run through the same problem before, as everyone who use GroovyScriptEngine will face.
My approach is to write my own ScriptEngine, cause as I see the implementation of the official one is pretty basic, <1k LOC.

AtomGroovyScriptEngine was implemented with both performance and ease of use in mind:

  • Cached class is one idea.
  • Hack the ClassLoader; try to resolve the dependencies in only specific group of classes and instance which hinted by the user registration with ScriptEngine.
  • More concurency and parallel in class loading and instance replacing.
  • More API for user to direct the ScriptEngine.

Anyway, I have to say combine the official ScriptEngine and cached class are almost solve the problems. Do you have any other ideas?

1 Like

I just plain don’t use the script engine any more. I instead cache the compiled scripts in a jme AssetLoader. I don’t worry about reloading the scripts once they are loaded since the user (developer) will just open the groovy console and plunk the script in there. But that is only my specific use case.
Some of the other problems with the official GroovyScriptEngine is its constant checking if the script files are changed, that slows it down a lot too.

One improvement can be using the @CompileStatic annotation in scripts. I haven’t benchmarked this but it apparently can help speed things up.

Keep up the good work on the wiki page…

2 Likes
<cite>@toolforger said:</cite> Heh. I'd love to go Groovy myself, but I've been finding it very hard for me to explore the set of methods that a passed-in object supports. I'm not sure how people in the dynamic programming camp deal with this; do they simply learn the entire standard libraries by heart, or do they do something simpler?

First every scripting language got the same type-safe dilemma. If you invest too much into Scripting, you fall immediately the mess that hidden errors that very hard to find.
The balance between benefit and hell of Scripting is thin. Duck-typing is not always a win-win.

From my experience, just ask you self, how “natural” your code are coded, in OOP sense:

Chicken.eat(rice) <= You know what methods and their parameter’s type, and name.
Monkey.eat(banana) <= You know what common in classes in a package. Without knowing the inheritance and interface they implemented.
Human.eat([chicken,rice,banana]) <= You can guess Human are derivated from Monkey and code are coded flexible, ex: methods are multi-type, optional param. etc…

If it have that level of “natural” sense, you don’t have to learn by heart at all, so use scripting in the situation.

In other hand, this very related to IDE support for such language. If you watch closely, Groovy going to have better support in Netbean:
https://blogs.oracle.com/netbeansgroovy/entry/groovy_refactoring_in_netbeans

1 Like
<cite>@Sploreg said:</cite> I just plain don't use the script engine any more. I instead cache the compiled scripts in a jme AssetLoader. I don't worry about reloading the scripts once they are loaded since the user (developer) will just open the groovy console and plunk the script in there. But that is only my specific use case. Some of the other problems with the official GroovyScriptEngine is its constant checking if the script files are changed, that slows it down a lot too.

One improvement can be using the @CompileStatic annotation in scripts. I haven’t benchmarked this but it apparently can help speed things up.

Keep up the good work on the wiki page…

Thanks, i’m glad that you guys see this topic useful!
The @CompileStatic is good in the performance improvement purpose but it simply kill the dynamic semantic and can not roll-back in run-time. That mean once the class are Static, they can never be Dynamic anymore! So this feature should be use with cares.

Anyway, it neary helps Groovy reach the speed and performance of Java in every aspects, even loading time and run-time. I have to say this feature is just freaking genius :stuck_out_tongue: For a loong time, I never seen anything that so muach fit with “best of both worlds” and it still get improved every single month…

Cheers,

I think it’s neat to see so many people using groovy in their games. It will really advance the “state of the art”, I think.

I find I follow a common pattern in my scripting solutions… enough that I eventually created a “ScriptEnvironment” class to package it all up. Basically, I like the scripts to feel a little DSL-like and so for a particular type of script I like to preload some API scripts into the environment. I essentially cut and pasted my ScriptEnvironment class when making Lemur’s style loader. You can see that here:
http://code.google.com/p/jmonkeyplatform-contributions/source/browse/trunk/Lemur/src/com/simsilica/lemur/style/StyleLoader.java

It preloads this script to make it easier to create styles in a more natural way:
http://code.google.com/p/jmonkeyplatform-contributions/source/browse/trunk/Lemur/src/com/simsilica/lemur/style/StyleApi.groovy

Then you can create styles like:
[java]
selector( “bookSpine” ) {
font = font(“Interface/knights32.fnt”)
color = color( 0.4f, 0.4f, 0.2f, 1f)
shadowColor = color( 0, 0, 0, 1f );
}
[/java]

…or with any arbitrary groovy code required.

I’m not sure if Groovy has a more natural way to implement this pattern but this is what I came up with over the last two years or so of Mythruna’s groovy integration.

Anyway, thought someone might find it interesting if it’s not already a common approach… and maybe I learn something if there is a better way. It’s nice and straight-forward, though.

@pspeed: Yeah, think of ideas that can be shared to improve both Groovy and JME3 at the same time.

Groovy has Builder, I guess you already know.

The idea behind BuilderSupport is:
to handle a Node - as a Method call in a Builder body as “defined route to do something”.
under the hood, its call MetaMethod with one,two,three parameters of type Closure,Object or Map.
It’s that simple, look at the code in the link!

http://groovy.codehaus.org/Make+a+builder
http://docs.codehaus.org/display/GROOVY/FactoryBuilderSupport

If you want the Builder has sub Builders,make it more plugable, use FactoryBuilder. Combine the Builder pattern and the Factory pattern.
May be the source of SwingBuilder will help.

I also use the same architect to make my own Nifty Builder, Spatial Builder … and few others…


About the pattern and the syntax of your above example, at the first glance, remind me of JQuery, which I also use a lot.
With Groovy DSL appearance you can make it work as you like, and familiar with. If you familiar with JQuery, yes, this syntax is nice and pretty intuitive.
Thoughts:

  • You can assign property directy (good for bean-like, StyleSheet is one good example, bad for complicated things that should be wrap by methods)
  • You almose use delegate, from my POV is somehow can be replace with the Factory pattern for better understanding… (i’m not a big fan of Design pattern anyway! )

Talking about what JQuery bring to JavaScript, I also do researches for other JS libraries (Backbone,underscore…) syntax & those functional, DSL feeling that they bring to JS language. At last I think about how to bring it to Groovy. You know, familiar syntax, more audiences.
:roll:

P/s: We should talk more about the ideas you used, I’m glad to know. :wink:

The API is supposed to act like a DSL but still have all of the groovy scripting goodness in it. That’s why it preloads the API as just some standard closures/methods.

For example, that same style file has this in it also:
[java]
selector( “mainTitle” ) {

font = font("Interface/akbar64.fnt")
color = color(0, 0, 64f/255, 1f)
fontSize = 136

def bg = TbtQuadBackgroundComponent.create( texture( name:"Interface/drawn-box-128.png", 
                                                     anisotropicFilter:4 ),
                                            2.0f, 5, 5, 123, 123,
                                            0.02f, true );
bg.setMargin(25,0);    
background = bg;

}
[/java]

So I can still setup more complicated or custom objects even if the DSL doesn’t support them directly.