godot-kotlin-native icon indicating copy to clipboard operation
godot-kotlin-native copied to clipboard

Add JVM/JNI target for local development

Open JustinMullin opened this issue 4 years ago • 11 comments

Describe the problem or limitation you are having in your project: The Kotlin/Native compiler is very slow at present, resulting in fairly long turnaround for small game code changes using godot-kotlin during development.

Describe how this feature / enhancement will help you overcome this problem or limitation: For local development, running game logic on the JVM rather than native code would allow for quick re-compile times, as well as some JVM niceties such as live class reloading at runtime and direct debugging+breakpoints into the Kotlin code. The Kotlin/Native implementation in godot-kotlin can then be used in the exported game to remove the dependency on the JRE.

Describe implementation detail for your proposal (in code), if possible:

  • Core+generated classes in godot-kotlin are extracted as Kotlin Multiplatform expect declarations. Native implementations of these classes will acquire actual keywords to define them as platform implementations, but otherwise remain unchanged.
  • Kotlin/JVM actual implementations are created utilizing external methods to call out to Godot APIs; implementations will be registered by the JNI later.
  • Game logic uses the same code as before, but for local development is compiled using the standard Kotlin/JVM compiler and the JVM actual implementations rather than the Kotlin/Native compiler against the existing implementations. The output classes are bundled to a JAR and output into the Godot project path.
  • A GDNative library is created which links to the JDK. This library is relatively project agnostic and shouldn't need to be recompiled during regular development. Upon gdnative_init, it instantiates a JVM via the JNI API, including the game logic JAR on the classpath. This initialization process also registers implementations for the JNI bindings above, allowing the JVM code to interface indirectly with GDNative. The implementations would be largely pass-through, but need to handle a bit of memory management and translation as the signatures for the external methods don't support pointer types, etc.

Is there a reason why this should be in this project and not individually solved?: Ideally a JVM+JNI implementation will be maintained in parallel to the Kotlin/Native version to ensure seamless transition between fast local development and export.

JustinMullin avatar Feb 06 '20 22:02 JustinMullin

Sorry if this is a bit hand-wavey on implementation details. I was able to get some basic game logic running on the JVM and interfacing bidirectionally with Godot with the design described above. Working on cleaning up a local POC of this that I had built against MrAkakuy's project. It had some rough edges and is now pretty out of date with the updates you folks have been making (more so if the refactorings to use Poet go through), so not the most usable thing in current state.

JustinMullin avatar Feb 06 '20 22:02 JustinMullin

Just realized the kotlinpoet stuff is already in (for the most part?), so scratch that bit. Will aim for a minimal demo of the above to more clearly show what I'm picturing, but wanted to at least kick off a discussion here, and get a feeling for whether or not this is controversial.

JustinMullin avatar Feb 06 '20 22:02 JustinMullin

@JustinMullin That is a great idea overall! And exactly what @lassem asked for on discord. The problem with this approach is the following: We discussed using expect and actual for all godot api calls so the user can write his code in common (we discussed it in a different context but anyways). We opted against it because as soon as the user wants to use another native library he has to maintain 2 modules (common and native) to be able to interact with it. It gets even worse if he has to write jni to be able to interact with it.

That said i personally think it's a great idea anyways because most users probably really only need the interaction with godot and thus writing the whole game logic in common would work for them. And for this majority of users your idea would really be helpful. Maybe we could get this approach working on an opt in basis. Per default we don't use jvm for local development, but if the user says (ex in the gradle.properties) that he want so use jvm for local development we could activate it.

To summarize: I really like your idea, but on an opt in basis. Also it would not have a high priority right now as we have to finish rewriting the code and improve the overall user experience first. But you said you had a working POC. So if you have time and are interested in it, please feel free to contribute and show your POC in a branch so we can look at it and discuss how we would integrate it.

Looking forward to your contribution :-)

chippmann avatar Feb 07 '20 06:02 chippmann

Starting from Kotlin 1.4, Jetbrain will be rewritting the whole Kotlin compiler ( a new unified one for JS/JVM/Native, so far the Native compiler has been a standalone tool). The speed up will be gradual so we can't expect lightspeed compilation time for Kotlin native in the coming months.

So I have mixed feelings about this. On one side, It's a pretty cumbersome feature, requiring 2 different implementations, and meant to be a temporary fix for the slow compiler. On the other side, we don't know how fast Kotlin Native will improve in the near future, and we might wait for an improvement that will never come.

But if this project exists, it's because we believe in Kotlin Native potential in the first place. But I have no experience with JNI so I don't know how complex it might be to implement. But if you can propose a POC, I have no issue with that.

CedNaru avatar Feb 07 '20 11:02 CedNaru

As a developer writing a Godot game in C# who normally is primarily a Kotlin developer, the biggest thing keeping me from switching to this project at this very moment is the fact that Kotlin/Native takes an incredibly long time to compile, so easy iteration and testing is difficult when compared to C#. The ability to quickly test and run Kotlin code would make this invaluable.

That said, the differences between K/N and Kotlin on JVM would make this difficult. For example, the fact that Singleton objects are frozen at runtime in K/N is fundamentally different from the JVM version, and would trip you up when compiling with JVM while developing the game (then switching and realizing these objects are frozen).

That being said, I would still absolutely benefit from this feature. It might almost be preferable to have just a standard JNI/JNA link instead and do a JVM only version, instead of trying to wrangle K/N and JVM in the same project. I'd love to see what you can come up with.

ejektaflex avatar Feb 08 '20 07:02 ejektaflex

@JustinMullin If you are willing to work on this I would assign you this issue so we know that someone is working on it :-)

chippmann avatar Feb 08 '20 11:02 chippmann

Sure, absolutely.

JustinMullin avatar Feb 08 '20 15:02 JustinMullin

Is there any progress on this feature? I assume given that slow compile speed is still an issue with kotlin native this can be a huge time safer during development?

fkrauthan avatar Nov 21 '20 21:11 fkrauthan

@fkrauthan This feature is not currently in development as a local-dev option for a Kotlin/Native solution, but efforts have turned to the https://github.com/utopia-rise/godot-jvm project which would use a JVM runtime at release as well as in dev, as Kotlin/Native isn't where it needs to be for runtime performance either, unfortunately.

JustinMullin avatar Nov 21 '20 21:11 JustinMullin

Ah so currently the plan is to concentrate on a JVM only project and reconsider this project (and kotlin native) when it is more mature?

fkrauthan avatar Nov 21 '20 21:11 fkrauthan

Currently kotlin native is not ready (see in readme). We are currently developping a jvm variant, in module way, so that is is better integrated in engine. Some code will be shared between the two repos, like entry generation, api generation and core types. See on https://github.com/Utopia-Rise/godot-jvm

piiertho avatar Nov 21 '20 21:11 piiertho