Properly extend and use engine/module class in C++

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By alektron

Hey,
so I’ve successfully been playing around with GDNative but recently I ran into a problem.
Inside my C++ code I was using an instance of the OpenSimplexNoise class. This was working for a while but then I needed to add some simple functionality to the class.
To be a little more precice, I wanted to add a size to the noise function and when accessing values with coordinates outside of a specific range it should always return 1.0

So I extended the OpenSimplexNoise class and added a few methods. I did NOT implement it as shown in the GDNative documentation, which means I did not add the GODOT_CLASS macro, _register_methods etc.
I did not do this because I didn’t want to use my new class inside Godot but only in create and access it from C++.

This actually worked but I had to to create the object like so
ClampedOpenSimplexNoise* noise = (ClampedOpenSimplexNoise*)ClampedOpenSimplexNoise::_new()
The cast was neccessary because _new was returning a OpenSimplexNoise pointer.
Now this was actually working for a while but recently it was often the reason for some of my crashes (I can’t really tell what changed exactly).
I thought maybe this is just not the right way to do it.
So I tried fully implementing my class as it’s described in the documentation, “GODOT_CLASS” and all.
Now I can simply write
ClampedOpenSimplexNoise* noise = ClampedOpenSimplexNoise::_new()
without the compiler complaining but… it always crashes at runtime when calling _new().
No matter what I tried I just couldn’t get a stable result so here is my question:
What is the correct way to extend engine classes for use in C++ only.

:bust_in_silhouette: Reply From: DarrionOakenbow

(Assuming you’re inheriting from OpenSimplexNoise)

The _new method calls an internal godot method that only constructs an OpenSimplexNoise, unless you’ve overridden it.

What you’re doing here is calling the _new method, which can only construct an object of type OpenSimplexNoise, then casting the resulting pointer to a ClampedOpenSimplexNoise (a child class). C++ only allows treating an object’s pointer as if it was something higher up in the class hierarchy.

I see 3 options here:

  1. Add the macros to register the ClampedSimplexNoise class as normal. This will override the _new method and allow you to construct it properly. It won’t stop you from only using it in C++.

  2. Use the normal OpenSimplexNoise class, but use C++'s std::clamp or min/max functions to clamp the result yourself.

  3. Make a completely new SimplexNoise class, either from scratch or containing a Ref to a godot OpenSimplexNoise class, rather than inheriting from it.