Game scripting guidance needed

I’ve been meaning to develop a game scripting language with the following goals:

  • Fast content creation by both developers and players
  • Secure (so malicious user content cannot exist)
  • Familiar syntax
  • Interpreting variables, functions and ideally expressions
  • Delegate some method/function calls to the real java code
  • Subscribing to events and update loops

I’d like to use this for as many things as possible, ranging from game mode implementation through missions, all the way to atmosphere-building scripts.
The feature is still in early stages of planning so I’m just trying to look for some ideas on how I should best go about it.

_
Here’s a concrete example for the project I’m working on (Lightspeed Frontier, a space sandbox game):

Each script file has a “main” method to run on activation, and some other functions it may declare. Upon starting a session, a “global” script is run to define the game world: setting up star systems the player can visit.
Each star system would then recieve its own governing script that makes sure there are always enough NPCs around, relevant missions offered, and so on.
Missions would be seperate scripts aswell, showing dialogue, performing events, offering choices and reactions.

Here’s a small, ideal concept example of a script attached to a ship that becomes an ally of the player, and tries to attack the same targets (or become hostile if the player attacks it)

script companion {
    main() {
        setAllegience(getInt("entityID"), getAllegience(getInt("playerID"))); // sets this npc's "team" to the player's
        subscribeEvent("EntityFightEngaged", "targetUpdate"); // subscribes for an event trigger
    }
    targetUpdate(EntityFightEngagedEvent event) { // Combat between two entities has started
        if(event.aggressorID == getInt("playerID")) { // is this relevant to our friend
            if(event.attackedID == getInt("entityID")) // player attacked companion
                setAllegience(getInt("entityID"), -1); // turn hostile
            else
                setTarget(event.attackedID); // attack player's target
        }
    }
}

_
I’d like to achieve something like this, but I’m having a tough time finding a solution with acceptable compromises.

  • I have considered writing a parser for a custom language. This proved to be extremely time consuming and complicated. I touched onto ANTLR, but it seems to be a “nuclear” solution, requiring a lot of learning/work to get going, so I’d like to consider other options first.

  • Lua seems powerful but I don’t yet know if it’s secure, and it may be tricky to inject with Java, given how it seems to be more like its own virtual machine than something to interpret.

  • Don’t laugh but, I even looked at JSON, which sounds a like an unfitting idea, but with a parser that won’t mess with the order of elements, it seems like a “plan C”.

Thoughts?

Lua is probably what you want. The script won’t be able to call anything you don’t expose so it’s at least that secure.

It will be the least amount of work in the long run if the “secure” requirement is really that important.

Else, I generally recommend “groovy” for quick and easy setup. The syntax is similar to Java, can be extended, etc… you just can’t lock it down unless you write your own DSL. (And that’s certainly possible with Groovy also.)

It all hinges on that one requirement.

I use Groovy as there will never be a case where random clients upload scripts to some server. Just like when installing mods, the person running the game has to know that “anything can happen”. The “secure” part is not a requirement for me and I can boostrap groovy scripting in about three lines of code.

We’re thinking of steam workshop support so that makes it really important.
I’ll take a closer look at Lua, thanks!

Well, looking at your profile, you look like a lot of people that want to make an MMORPG on their own (without a team) and with little experience (like myself - who may or may not have more experience that you).
All that said,…
Can you read/write from a data base - to keep player info etc.? I keep my planet data in there. I use “net.ucanaccess.jdbc.UcanaccessDriver”

(um… have you check out what has already been done? Check out
http://orbit.medphys.ucl.ac.uk/
I can spend days playing with it.)
Assuming you know the basic paradigm…
input (optional - set flags)
move (use flags to change states)
draw (wait…)
I use (as a basic layout)

Utils.println("Main()"); 
setDisplayStatView(false); 
setPauseOnLostFocus(true); 
flyCam.setEnabled(false); 
cam.setFrustumNear(1f); 
cameraNode = new CameraNode("cameraNode", cam); 
// 
//Bullet is flat - everything gets added to rootNode, I'm working on an environment that handles things recursively - Earth gets added to the Sun, Moon gets added to Earth. 
//environmentAppState = new EnvironmentState(this, new Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE)); 
//or 
environmentAppState = new EnvironmentState(this);
stateManager.attach(environmentAppState); 
gameState = new GameState(cameraNode);//handle game specific stuff 
stateManager.attach(gameState) 
hudState = new HUDState();//dua 
stateManager.attach(hudState); 
inputState = new InputControllableState(inputManager, cameraNode);//handle input 
stateManager.attach(inputState); 

Check out the project that others (everyone ;-)) are working in solitude.

Parsing…
I have flags for thrust-up, thrust-down… Every iteration I have to test for each flags. I’m thinking of coding them so that a 1 accesses thrust-up flags without without all the testing.

I made a Rubick’s cube application and coded the rotation as the type (the whole cube or a set); what set (row, column, wall (face)); which set in the 3x3x3 cube; the direction; as numbers. That way, I could undo what I had already done. You should Google scripting.
If any of this looks good, let me know and I’ll send you more details.

Most modern MMOs will use an entity system to keep from driving the team crazy.

Zay-es is such an entity system and has database support built in. Just saying…

What about javascript?

Players will rarely study a new language just to mod your game, so you should use something that they already know, and javascript is quite widespread and is very similiar to other languages, so you can still figure it out even if you don’t know it specifically.

Lua may be the de facto scripting language for games, but you don’t find it a lot elsewhere, so unless someone is a devoted modder, he won’t probably know lua.

On top of that, js is already implemented in java8+.

Javascript is not as secure as Lua. You can essentially call anything in Java that’s exposed.

…as I recall, even System.exit() is available.

Lua has the advantage that the only thing that can be called are the things that you specifically expose… it has the disadvantage that everything that you want called has to be specifically exposed.

…unless there is something I’m missing.

You can use a ClassFilter for nashorn and whitelist only the apis you want .

Generally I consider game scripting to fall into one of three categories:

  1. Built-in scripts. These are anything you ship with your game where you used a script of some sort for parts of your game logic. Since you distribute this, you have no security requirements. For this category I’d definitely suggest Groovy. Any other JVM scripting language would also work, but I haven’t yet found anything to rival the power and simplicity of embedded Groovy scripts.

  2. Local mod scripts. These are anything the user can write/install to modify a local game. Security restrictions are moderate here - you don’t want to make it easy to cheat the game or cause an accidental crash, but any nasty code is just going to come around to bite the local user, so there’s no great risk of malicious code hurting someone else. Groovy is still a great fit here, and Nashorn JS has class filters (as previously pointed out) that also let you lock things down reasonably well.

  3. Remote scripts. Think custom user-created scripts running on a multiplayer server or being distributed to other clients on a wide scale. Security is extremely touchy here, and any exploitable loopholes probably can and will cost you and your users big time. Groovy could (with extensive analysis and custom compiler extensions) be used here, but in my assessment of this possibility a few years ago I concluded that they work and risk involved were too great, and I started designing my own scripting language, compiler, and interpreter that run on top of the JVM. There are many, many security issues here - CPU use, memory use, class access, etc. I needed a solution that could easily handle all three (memory is next to impossible on stock JVM languages like Groovy), and I needed to be able to arbitrarily suspend execution and resume on a different machine without any special considerations made by the script author. While I do not consider my new language to be “complete” yet, it is fairly far along - I’m currently working out how I want polymorphism to behave, and the interpreter has the groundwork and/or full implementation for securing all three “danger points” I listed above. If you go this route, ANTLR is a good tool but as you found it has its own quirks and pain points too (I ended up coding a handwritten recursive-descent parser for the compiler - not at all a small task, even for a “simple” language that’s clean and consistent). Your JSON idea sounds OK if you want to do a graphical node-based scripting setup like Unreal does with Blueprints, but it would be a massive pain to hand-write scripts in. JSON is a very descent data storage format, but coding in that will be ANT XML all over again.

1 Like