Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using TypedArray with an enum causes 'get_class_static' is not a member of ... #1584

Closed
ZacharieBeauchemin opened this issue Sep 14, 2024 · 6 comments

Comments

@ZacharieBeauchemin
Copy link

ZacharieBeauchemin commented Sep 14, 2024

Godot version

4.3

godot-cpp version

4.3

System information

Windows 11

Issue description

When creating a TypedArray the following error occurs:

error: 'get_class_static' is not a member of ...
set_typed(Variant::OBJECT, T::get_class_static(), Variant());

Steps to reproduce

Create an enum like so:

namespace Game {
    enum Direction {
        Up,
        Down,
        Left,
        Right
    };
}

VARIANT_ENUM_CAST(Game::Direction)

Try to use it as the type for a TypedArray like so:

godot::TypedArray<Game::Direction> sequence;

Minimal reproduction project

N/A

@aaronfranke
Copy link
Member

Does it work if you use MAKE_TYPED_ARRAY_INFO(Game::Direction, Variant::INT)?

@ZacharieBeauchemin
Copy link
Author

ZacharieBeauchemin commented Sep 18, 2024

I might be missing something but I don't seem to be able to use MAKE_TYPED_ARRAY_INFO. I tried to add it to the end of my Direction.hpp file after VARIANT_ENUM_CAST and also tried to add #include <godot_cpp/core/type_info.hpp> but it doesn't seem to be recognized.

I also tried to add what would be result of the macro directly in the Direction.hpp file but I still get the same error 'get_class_static' is not a member of 'Game::Direction'

#pragma once

namespace Game {
	enum Direction {
		Up,
		Down,
		Left,
		Right
	};
}

VARIANT_ENUM_CAST(Game::Direction)

namespace godot {
	template<>
	struct GetTypeInfo<TypedArray<Game::Direction>> {
		static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
		static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;

		static inline PropertyInfo get_class_info() {
			return make_property_info(Variant::Type::ARRAY,
			                          "",
			                          PROPERTY_HINT_ARRAY_TYPE,
			                          Variant::get_type_name(Variant::INT).utf8().get_data());
		}
	};

	template<>
	struct GetTypeInfo<const TypedArray<Game::Direction>&> {
		static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
		static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;

		static inline PropertyInfo get_class_info() {
			return make_property_info(Variant::Type::ARRAY,
			                          "",
			                          PROPERTY_HINT_ARRAY_TYPE,
			                          Variant::get_type_name(Variant::INT).utf8().get_data());
		}
	};
}

@BenLubar
Copy link

BenLubar commented Oct 4, 2024

It looks like it compiles to something that shows up in Godot as Array[int] if I include both the MAKE_TYPED_ARRAY_INFO and MAKE_TYPED_ARRAY macros.

Edit: if I replace the Variant::get_type_name expression with enum_qualified_name_to_class_info_name("Game::Direction"), it shows the correct name in the documentation but links to the nonexistent class Game.Direction rather than the enum within the Game class.

@ZacharieBeauchemin
Copy link
Author

@BenLubar Thanks, using both MAKE_TYPED_ARRAY_INFO and MAKE_TYPED_ARRAY works! Although like I mentioned for some reason I had to expand the macros instead of just doing this:

MAKE_TYPED_ARRAY(Game::Direction, godot::Variant::INT)
MAKE_TYPED_ARRAY_INFO(Game::Direction, godot::Variant::INT)

As for showing up in Godot as Array[int] I don't know if there is anything that can be done but at using ADD_PROPERTY like this works to have a dropdown.

ClassDB::bind_method(D_METHOD("set_sequence", "sequence"), SetSequence);
ClassDB::bind_method(D_METHOD("get_sequence"), GetSequence);
ADD_PROPERTY(
  PropertyInfo(Variant::ARRAY, "sequence", PROPERTY_HINT_TYPE_STRING, String::num(Variant::INT) + "/"
    + String::num(PROPERTY_HINT_ENUM) + ":Up,Down,Left,Right"),
  "set_sequence",
  "get_sequence");

@dsnopek
Copy link
Collaborator

dsnopek commented Oct 5, 2024

@ZacharieBeauchemin That seems about right to me!

@ZacharieBeauchemin
Copy link
Author

Ok for anyone stumbling here in the future and wondering why they can't use MAKE_TYPED_ARRAY and MAKE_TYPED_ARRAY_INFO I found the answer. I don't know why I didn't notice sooner but they get undefined with #undef at the end of their respective .hpp files.

So unless someone has a better solution (which may well exist since I am quite new in C++ and gdextension in general) I ended up just copying the expanded macros like this:

namespace godot {
	// Expanded macro MAKE_TYPED_ARRAY(Game::Direction, godot::Variant::INT)
	template<>
	class TypedArray<Game::Direction> : public Array {
	public:
		_FORCE_INLINE_ void operator=(const Array& p_array) const {
			ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type.");
			_ref(p_array);
		}

		_FORCE_INLINE_ TypedArray(const Variant& p_variant) : TypedArray(Array(p_variant)) {}
		_FORCE_INLINE_ TypedArray(const Array& p_array) {
			set_typed(Variant::INT, StringName(), Variant());
			if (is_same_typed(p_array)) {
				_ref(p_array);
			} else {
				assign(p_array);
			}
		}

		_FORCE_INLINE_ TypedArray() {
			set_typed(Variant::INT, StringName(), Variant());
		}
	};

	// Expanded macro MAKE_TYPED_ARRAY_INFO(Game::Direction, godot::Variant::INT)
	template<>
	struct GetTypeInfo<TypedArray<Game::Direction>> {
		static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
		static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;

		static PropertyInfo get_class_info() {
			return make_property_info(
				Variant::Type::ARRAY,
				"",
				PROPERTY_HINT_ARRAY_TYPE,
				Variant::get_type_name(Variant::INT).utf8().get_data());
		}
	};

	template<>
	struct GetTypeInfo<const TypedArray<Game::Direction>&> {
		static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
		static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;

		static PropertyInfo get_class_info() {
			return make_property_info(
				Variant::Type::ARRAY,
				"",
				PROPERTY_HINT_ARRAY_TYPE,
				Variant::get_type_name(Variant::INT).utf8().get_data());
		}
	};
}

Having to do this seems a bit weird to me but at least it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants