Description
Introduction and motivation
I've been working with the kotlin API quite a lot in the last couple of weeks. While I'm very happy with it in general, one of the papercuts is the @Register
family of annotations (@RegisterClass
, @RegisterFunction
and @RegisterProperty
).
Imagine the following scenario:
@RegisterClass
class MyButton : Button(){
override fun _onReady(){
GD.print("hello world!")
}
}
This will never print anything. Why? Because _onReady
needs to be annotated with @RegisterFunction
. I've lost count of how many times I was pulling my hair why some action wouldn't trigger in my game, and in 90% of all cases it was because I was missing an annotation. The information is also redundant: we're overriding a function of the Godot API. Of course we want Godot to "see" it, why wouldn't we?
To reduce this pain, and just get rid of a pitfall, I propose the following set of rules where the Godot gradle plugin should automatically register classes, functions and properties, no matter if they're annotated or not.
Rules for auto-registration
- Every
class
which directly or indirectly inherits fromgodot.Node
(and is notabstract
) should be treated as if it was annotated by@RegisterClass
.
It prevents anyone from forgetting it, and there is no use case for a subclass of
godot.Node
that isn't usable in the editor. Conversely, with this rule, I would argue that the explicit@RegisterClass
annotation can be deprecated and marked for removal. It is always a mistake to annotate a class with@RegisterClass
if it doesn't inherit directly or indirectly fromgodot.Node
as Godot will not know what to do with it.
- Every function which is an
override
of a function ofgodot.Node
or its subclasses in thegodot
namespace should be treated as if it was annotated by@RegisterFunction
.
For example,
override fun _onReady(){}
should be enough, there's no need for@RegisterFunction
. There is no use case for overriding a Godot-defined API that shouldn't be visible to Godot.
- Every property which is annotated as
@Export
should also be treated as if it was annotated by@RegisterProperty
.
There is no use case where we want to export a property to the Godot editor and hide it at the same time. The inverse however is not true: a property which is marked as
@RegisterProperty
should not necessarily show up in the editor, which justifies the distinction between@Export
and@RegisterProperty
.
Implementation considerations
All three rules are detectable with reasonable effort (both on the gradle plugin authors side as well as in terms of runtime overhead) via JVM reflection. No rule requires method bodies to be inspected, therefore all rules can be evaluated via the reflection API alone; no source code scanning is required. The most expensive part will be scanning the user project for classes, but this already needs to happen in the existing gradle plugin to find the annotated classes.
I would also be willing to help out with the implementation of these rules if needed, as long as I can code it in Java or Kotlin. I have a fair amount of experience with JVM reflection from my day job.