Is it worth to use nashorn ?

Hello,

I’ve been experimenting with nashorn lately and I have a few questions about it.

Firstly, I wanted to create scripts for events(onUnitDeath, on…) to let the user customize it without having to recompile the game and I’m not sure if it is a good idea to do it this way.

Secondly, is it possible to disable/prevent Java code from being run within JavaScript code ?
I asked this one, because some people can simply call the “java.io.File.delete()” function and other functions like that and because I don’t plan on using it for the client side ?

Thanks in advance for your help.

An issue with using different languages is that you have to bridge between them. This is rather messy, and getting it secure is very complex. Regardless of the ‘scripting language’, how do you expect to handle, say, an infinite loop? If you want the least amount of bridging between languages, make Java the scripting language, by using Janino (runtime java->bytecode compilation). You can use Java’s bytecode transformation library ASM to validate the generated bytecode (validating plain sourcecode is too complex), by whitelisting method calls (not blacklisting them). After that you simply load the bytecode with a ClassLoader.

Last but not least: this is quite an advanced topic, are you sure you want to even support end-user scripting?

I agree with @Riven about using Java. You may potentially find Janino somewhat limiting though - it’s missing some useful language support (eg. enums and runtime annotations). In the Praxis LIVE repositories you can find a forked version of Janino and a refactored javac should that be useful.

The compiler is Java 7 currently - will be adding Java 8 version in the new year. Fairly easy to refactor though - it’s mostly changing package declarations, some in strings IIRC.

Setting up the classpath is a little more complicated than vanilla Janino though.

Personally I’m dubious about using ASM to do security management in this way. If it’s for the user’s own use, why bother with the complexity. And if you’re expecting users to share scripts then I think it’s probably better to assume caveat emptor than set up expectations that you’ve closed every loophole.

@Riven - I would be interested in your thoughts on handling an infinite loop in this situation though.

https://en.m.wikipedia.org/wiki/Halting_problem :wink:

Thanks for the link! Bear in mind @Riven said “handling” though. Handling the possibility is not the same as proving it will occur! :wink:

Can you really handle the possibility when you don’t know if it will occur? Maybe it only needs 1 cycle more to finish.

Well, by definition an infinite loop won’t finish in 1 more cycle! :wink: However, I understand your point. But, who cares? If we’re talking in the context of a game, or any other real-time situation, you want code with a maximum bounded execution time? In that situation code that exceeds that contract is invalid and should be disabled. But how to do that without potentially leaving invalid state and/or making the code run substantially slower - eg. one thought I’d had was a monitoring thread and injecting a check on a volatile flag into every loop.

Who needs enums and runtime annotations for handling an [icode]onUnitDeath(…)[/icode] event :point:

I needed runtime annotations for what I wanted to do, which is admittedly more complicated than your example. The annotations are used to define behaviour and / or inject variables into the “scripts”. It can lead to much simpler user code. Imagine you’ve got 10’s or 100’s of such onXSomething() style hooks, and the user wants to run a fragment of code on a subset of them - you can define annotations to filter the conditions such code is run and help the engine manage scripts more easily.

It depends on the level of flexibility around connections / maintaining state you require. Simple example of how I’m using annotations is here - https://youtu.be/5R_ZJdYLpow