Trying to add a Vector as a property in _bind_methods (GDExtension)

Godot Version

4.2.2

Question

Hello!

I am creating a custom mesh class for terrain (from a noise texture), and would like to save the height map as a property. I currently have it stored as Vector<Vector<float>>*. Is there a way for me to save it as a property so that it can be serialized and saved?

My understanding is that this is how the height map would be able to be loaded from the saved scene. I don’t think it would be ideal to have to re-create the mesh and height map every time the game runs.

To my knowledge, you can only bind these types of properties.


If you have any other suggestions, please let me know!

So far I have tried:

  • using a TypedArray<TypedArray<float>>, but it seems that when I try this, indexing into the 2D array returns an Object instead of a float.
  • storing a secondary PackedFloat32Array and loading from that – THIS WORKS!

I will edit the post as I try other things (rather than replying to it).
Other Edit: mistake in the type I was trying before


Thank you for your time! :slight_smile:

Hello,

Use ressources. Inherit from resource and add Vector<Vector<float>>* as a property of your class and flag it as Export. Then save/load that resource file as usual.

May I ask how you would save it as a property in _bind_methods? My mesh class inherits Resource via ArrayMesh. Or how to flag it as Export? I thought that in GDExtension the only way to export properties was via the _bind_methods function.

I am having a hard time figuring out the correct way to form the PropertyInfo() to add the property to begin with. :sweat_smile:

I will keep trying in the interim! Thank you for your time.

(If you didn’t realize that this was a GDExtension question, no worries at all! I just realized that I should have made it more clear instead of just putting it in the tags.)

ah yes indeed, sorry i can’t help then.

No problem! Thank you for your time regardless. :slight_smile:

Update

I have had success with storing a secondary PackedFloat32Array.
Note: I also realized that I had no reason to store the outer Vector as a pointer, so that has been changed from my original question.

Excerpt from .h file:

	Vector<Vector<float>> height_map;
	PackedFloat32Array packed_height_map; // for serialization

	void save_height_map_to_packed(); // called after the height map is generated and the mesh arrays have been created
	void load_height_map_from_packed(); // the custom MeshInstance3D class I made calls this in _enter_tree

My _bind_methods looks like this:

void TerrainMesh::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_width", "width"), &TerrainMesh::set_width);
	ClassDB::bind_method(D_METHOD("get_width"), &TerrainMesh::get_width);

	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width"), "set_width", "get_width");

	ClassDB::bind_method(D_METHOD("set_depth", "depth"), &TerrainMesh::set_depth);
	ClassDB::bind_method(D_METHOD("get_depth"), &TerrainMesh::get_depth);

	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth"), "set_depth", "get_depth");

	ClassDB::bind_method(D_METHOD("set_array_width", "array_width"), &TerrainMesh::set_array_width);
	ClassDB::bind_method(D_METHOD("get_array_width"), &TerrainMesh::get_array_width);

	ADD_PROPERTY(PropertyInfo(Variant::INT, "array_width"), "set_array_width", "get_array_width");

	ClassDB::bind_method(D_METHOD("set_array_height", "array_height"), &TerrainMesh::set_array_height);
	ClassDB::bind_method(D_METHOD("get_array_height"), &TerrainMesh::get_array_height);

	ADD_PROPERTY(PropertyInfo(Variant::INT, "array_height"), "set_array_height", "get_array_height");

	ClassDB::bind_method(D_METHOD("set_x_offset", "x_offset"), &TerrainMesh::set_x_offset);
	ClassDB::bind_method(D_METHOD("get_x_offset"), &TerrainMesh::get_x_offset);

	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "x_offset"), "set_x_offset", "get_x_offset");

	ClassDB::bind_method(D_METHOD("set_z_offset", "z_offset"), &TerrainMesh::set_z_offset);
	ClassDB::bind_method(D_METHOD("get_z_offset"), &TerrainMesh::get_z_offset);

	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "z_offset"), "set_z_offset", "get_z_offset");

	ClassDB::bind_method(D_METHOD("set_terrain_square_conversion", "terrain_square_conversion"), &TerrainMesh::set_terrain_square_conversion);
	ClassDB::bind_method(D_METHOD("get_terrain_square_conversion"), &TerrainMesh::get_terrain_square_conversion);

	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "terrain_square_conversion"), "set_terrain_square_conversion", "get_terrain_square_conversion");

	ClassDB::bind_method(D_METHOD("set_packed_height_map", "packed_height_map"), &TerrainMesh::set_packed_height_map);
	ClassDB::bind_method(D_METHOD("get_packed_height_map"), &TerrainMesh::get_packed_height_map);

	ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "packed_height_map"), "set_packed_height_map", "get_packed_height_map");
}

(I was originally having problems with it crashing since I hadn’t bound some of the other properties and ended up dividing by 0.)


I don’t think this is the answer though…

However, since this doesn’t actually solve the problem of adding a Vector as a property in GDExtension, I will not set this as an answer. Hopefully this update can still help if anyone gets into a similar position to where I was this morning!

If I somehow confirm that there is no way to add a Vector as a property, I will set this as the solution at that point.