Skip to content

A proposal for reducing the need for @Register annotations #606

Open
@MartinHaeusler

Description

@MartinHaeusler

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

  1. Every class which directly or indirectly inherits from godot.Node (and is not abstract) 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 from godot.Node as Godot will not know what to do with it.

  1. Every function which is an override of a function of godot.Node or its subclasses in the godot 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.

  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions