Referencing Current Terrain3D Instance in C# (EDIT: Solved!)

Godot Version

4.2.2 mono stable

Question

EDIT with solution: For any future travelers who find themselves stuck like me, you want to use the following syntax to access the appropriate properties and methods. In this example, I’m getting the storage property and calling the get_texture_id method:

terrain.AsGodotObject().Get("storage").AsGodotObject().Call("get_texture_id", GlobalPosition)

Hope my floundering and eventual success hopes someone else!

ORIGINAL POST:
I am trying to access an existing Terrain3D node within my scene in a C# script, specifically to call a method on Terrain3DStorage.

I am struggling with the information given on the plugin’s Integrating with Terrain3D documentation, and when I asked in the Discord the creator said I must be missing some element of how Godot and C# interact, which is entirely likely coming from Unity.

There is a section about instantiating and calling in C#, but I’m fairly certain I don’t want to instantiate because I’m trying to access an existing instance, right?

     var terrain = ClassDB.Instantiate("Terrain3D");
     terrain.AsGodotObject().Set("storage", ClassDB.Instantiate("Terrain3DStorage"));
     terrain.AsGodotObject().Set("assets", ClassDB.Instantiate("Terrain3DAssets"));
     terrain.AsGodotObject().Call("set_collision_enabled", true);

The code given for capturing an existing instance is in GDScript:

     var terrain: Terrain3D # or Node if you aren't sure if it's installed
     if Engine.is_editor_hint(): 
          # In editor
          terrain = get_tree().get_edited_scene_root().find_children("*", "Terrain3D")
     else:
          # In game
          terrain = get_tree().get_current_scene().find_children("*", "Terrain3D")

     if terrain:
          print("Found terrain")

Some of the methods don’t appear to exist in the same way in C#, and I can’t use Node or Node3D as then I can’t use the AsGodotObject() methods, but this seems to kinda work in its place to at least grab the instance:

private Variant terrain;

	public override void _Ready()
	{
		terrain = GetTree().GetNodesInGroup("Terrain"); //Note: Terrain3D node is in group "Terrain"
		GD.Print(terrain);
    	}

However, the GD.Print produces a console message of: [Terrain3D:[Wrapped:0]]

That message led me to this documentation which says it’s about C++…

So, basically, I’ve looked at a bunch of documentation and don’t know what the heck I’m doing wrong. I feel like I’m just missing something obvious about C# implementation in Godot even though so far I thought I had a pretty good handle on it. If anyone could kindly guide me in the right direction it would be appreciated.

EDITED to place this post in Programming like I initially intended.

1 Like

Thank You so much!
It helped a lot.

Based on your solution this is a short update on Godot 4.4 and Terrain3D 1.0 C#

Add your terrain3d node to a global group called “Terrain” like in the original answer.
Get your GodotObject from terrain3d class: data →
GodotObject terrainData = GetTree().GetNodesInGroup(“Terrain”)[0].Get(“data”).AsGodotObject();
Use one of the available method. For example get the terrain actual height in your player position. GD.Print(terrainData.Call(“get_height”, playerGlobalpos));

Here the all available method in terrain3d data class:
https://terrain3d.readthedocs.io/en/stable/api/class_terrain3ddata.html

Full example:

using Godot;
using System;

public partial class TerrainHelper : Node
{
public static GodotObject terrainData;
public override void _Ready()

{
    terrainData = GetTree().GetNodesInGroup("Terrain")[0].Get("data").AsGodotObject();
}

public float GetTerrainHeight(Vector3 itemGlobalpos)
{
    float height = (float)terrainData.Call("get_height", itemGlobalpos);
    if (Mathf.Abs(height) < 0.0001f)
    {
        height = 0.0f;
    }
    GD.Print(height);
    return height;
}
}