Skip to content

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

Closed

Description

@ZacharieBeauchemin

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

Activity

  1. aaronfranke commented on Sep 18, 2024

    @aaronfranke
    Member

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

  2. ZacharieBeauchemin commented on Sep 18, 2024

    @ZacharieBeauchemin
    Author

    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());
    		}
    	};
    }
  3. BenLubar commented on Oct 4, 2024

    @BenLubar
    Contributor

    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.

  4. ZacharieBeauchemin commented on Oct 4, 2024

    @ZacharieBeauchemin
    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");
  5. dsnopek commented on Oct 5, 2024

    @dsnopek
    Collaborator

    @ZacharieBeauchemin That seems about right to me!

  6. ZacharieBeauchemin commented on Oct 5, 2024

    @ZacharieBeauchemin
    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions