[Bf-gamedev] A new script interface for bge (in theory)

pgi pierluigi at tukano.it
Wed Jan 28 21:20:33 CET 2015


I hereby propose a new script interface for bge. I will also take care 
of it - once I figured out a couple of runtime issues with linking and 
resolving names. No coding needed, just ideas.

Currently bge scripting is done in Python. To be clear, that's perfectly 
fine: it makes sense to have one scripting language - and not a hundred 
- and it makes sense for it to be Python.

Here's the problem I see though.

The interface between the engine and the scripting layer is spread all 
over the place. Each engine element has its own little subset of the 
whole thing. The thing is in fact so tightly integrated that changing it 
would be a major undertaking.

Instead of doing that i made a couple of experiments with adding a new 
interface that will, with time, replace the older one. It can be made to 
work.

This is how the new system would work - more or less.

The engine presents itself to the scripting interface via a big 
collection of functions, much like an opengl interface. Things like this:

class ScriptInterface {
public:
     long findObjectId(std::string name) { ... }
     int getObjectType(long id) { ... }
     void setObjectLocalLinearVelocity(long id, float x, float y, float 
z) { ... }
     void getObjectLocalLinearVelocity(long id, float* buffer3) { 
...something... }
     ...and so on forever and ever...
}

So it's a huge set of relatively small function, defined in one file.
This is used by the scripting system to get data from the engine.

The script layer is defined in a dynamic library, with a interface like 
this:

void start(ScriptInterface* si)
void tick();
void stop();

 From the engine side, the scripting layer is then activated and ran 
like this:

...when the engine starts:
scriptlibrary = load_the_dll
ScriptInterface* si = new ScriptInterface(ketsy, scene list, maps, 
whatever is needed);
scriptlibrary.start(si);

...for each frame
scriptlibrary.tick();


...when the engine quits:
scriptlibrary.stop()
unload the dll if necessary

So there's very little to change in the actual code of the engine, and 
that little is just adding a couple of lines.

What's in the dynamic library.

In the jvm version:

start(ScriptInterface* si) -> stores si, starts the jvm, load the jvm 
script interface (a java class, BGEScriptContext)
tick() -> tick the BGEScriptContext, which in turn ticks all the scripts 
loaded on the jvm side
stop() -> signal the scripts to stop, kills the jvm
...
one jni function for each ScriptInterface function, like:
JNIEXPORT jlong 
Java_org_blender_bge_scripting_BGEScriptContext_findObjectId(JNIEnv* 
env, jclass cls, jstring name) {
     long id = scriptinterface.findObjectId(stdstringname)
     return id;
}

This is a trivial 1:1 mapping.

The third part is this BGEScriptContext class, which looks like this:

public class BGEScriptContext {
     static { System.loadLibrary(...the aforementioned dll...) }
     ...for each ScriptInterface function
     ...the corresponding static method, like
     public static native long findObjectId(String name);
     public static native void setObjectLocalLinearVelocity(long id, 
float x, float y, float z);
     ...
}

Another long, boring but still very trivial 1:1 mapping.

And that's it. Once you have this big java class in place, all the 
languages that run on the jvm can access the bge engine functions. You 
can have it in python scripts:

import BGEScriptContext

id = BGEScriptContenxt.findObjectId(name);

in java, in scala, in lua, in javascript. More so, on top of the raw 
BGEScriptContext one can build a structured interface, without the need 
to interfere with the engine code. So one can have a Scenegraph type 
that gives the scripters access to BgeGameObject types (that the 
scenegraph will secretly build from ids).

Advantages i see over the current system.

 From the engine perspective:

1. the script interface is defined in one place, which makes it easier 
to maintain, extend and - in case of an excess of love - transplated as 
it is in case of radical upgrades to ketsji
2. the engine doesn't have to know how the scripting interface runs, it 
just loads a dll and calls a total of four functions.

 From the scripting perspective:

1. because of the dynamic linking, the script counterpart can be 
replaced (wanna pass from jvm to mono? Just create a new dll with the 
same load(ScriptInterface), tick() and stop() functions. Well, at least 
that how I think dll works.).
2. using a proper virtual machine allows to support multiple languages 
with a single interface to maintain. That's for free. For the jvm, once 
you get that BGEScriptContext class in place, you can code in Python, 
Java, Javascript, LUA, Kotlin, Scala, Pizza, Prolog (there is still 
someone using prolog!), C, Pascal. Take that Crytek.

And I sincerely hope this mail doesn't come back from the mailing list 
serve, flagged as spam, because it took me a long time to write it.

I'd like to know if anyone has any thoughts on this subject.


More information about the Bf-gamedev mailing list