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

Recursive error in internal::no_duplicate_field_names #350

Open
AnsiV01 opened this issue Feb 12, 2025 · 0 comments
Open

Recursive error in internal::no_duplicate_field_names #350

AnsiV01 opened this issue Feb 12, 2025 · 0 comments

Comments

@AnsiV01
Copy link
Contributor

AnsiV01 commented Feb 12, 2025

Hi

Today, as usual, I worked on a hobbyist game that I use reflect-cpp to work on. But today, after adding some values to an enum class, I got an error which is hard to copy.

The main error in MSVC reads:
C1202 recursive type or function dependency context too complex

In a nutshell, it looks like there's something wrong in the function internal::no_duplicate_field_names in the file rfl\internal\no_duplicate_field_names.hpp.

Unfortunately, I had a hard time mapping the same problem in an extracted project using the same structures (which was no easy task), which makes the bug look all the more like the one from the WTF cycle

Below I attach the code I managed to extract from the main project, but I can't get the same error on it

Code
#include <rfl/json.hpp>

constexpr uint64_t ITEM_MUTABLE_ATTRIBUTE_COUNT = 3ULL;
constexpr uint64_t ITEM_VALUES_COUNT = 3ULL;
constexpr uint64_t ITEM_SOCKET_COUNT = 6ULL;

enum class Attribute : unsigned char
{
	NONE,

	LEVEL,
	EXP,
	BASIC_ATTRIBUTE_POINT,

	STRENGTHENING_ALL_ATTRIBUTES,

	BASIC_VITALITY,
	VITALITY,
	BASIC_INTELLIGENCE,
	INTELLIGENCE,
	BASIC_STRENGTH,
	STRENGTH,
	BASIC_DEXTERITY,
	DEXTERITY,
	BASIC_PRECISION,
	PRECISION,
	BASIC_FOCUS,
	FOCUS,

	MOVE_SPEED,
	ATTACK_SPEED,

	HEALTH_POINT,
	MAX_HEALTH_POINT,
	MAX_HEALTH_POINT_PERCENT,
	PASSIVE_HEALTH_POINT_REGEN_PER_SECOND,
	ACTIVE_HEALTH_POINT_REGEN_PER_SECOND,
	ACTIVE_HEALTH_REGEN_POINT,

	MANA_POINT,
	MAX_MANA_POINT,
	MAX_MANA_POINT_PERCENT,
	PASSIVE_MANA_POINT_REGEN_PER_SECOND,
	ACTIVE_MANA_POINT_REGEN_PER_SECOND,
	ACTIVE_MANA_REGEN_POINT,

	BASIC_PHYSICAL_ATTACK_DAMAGE,
	MIN_BASIC_PHYSICAL_ATTACK_DAMAGE,
	MAX_BASIC_PHYSICAL_ATTACK_DAMAGE,
};

struct ItemData
{
	short count{};
	std::array<std::pair<Attribute, long long>, ITEM_MUTABLE_ATTRIBUTE_COUNT> mutable_attributes{};
	std::array<long long, ITEM_VALUES_COUNT> values{};
	std::array<uint32_t, ITEM_SOCKET_COUNT> sockets{};
	long long time_limit_value{};
};

enum class SlotType : unsigned char
{
	NONE,

	INVENTORY,
	ARMAMENT,
	QUICK,
	MAGAZINE,

	CLIENT_SKILL,
	CLIENT_SHOP,
	CLIENT_EXCHANGE_OWN,
	CLIENT_EXCHANGE_SOMEBODY,
	CLIENT_DROP_INFO_MONSTER,
	CLIENT_DROP_INFO_BOX,
	CLIENT_REFINE,
};


struct ItemPosition
{
	SlotType type;
	uint64_t position;
};

struct PacketSCCreateItem
{
	ItemPosition slot{};
	uint64_t prototype_id{};
	ItemData item_data{};
	bool is_active{};
};

struct Position
{
	float x{};
	float y{};
	float z{};
};

enum class WearWeaponMode : unsigned char
{
	NONE,
	WEAPON_SWORD,
	WEAPON_BOW
};

enum class AttributeSource : unsigned char
{
	UNKNOWN,
	BASE,
	ITEM,
	AFFECT,
	GROUP,
	PASSIVE_SKILL,
	ATTRIBUTE_BONUS,
};

struct PacketSCSetAttribute
{
	uint64_t virtual_id{ 0 };
	Attribute attr{};
	long long value{};
	//std::array<long long, ecpp::enum_size<AttributeSource>> sources{};
	std::array<long long, 7> sources{};
};

struct PacketSCAddToQuickslot
{
	uint64_t slot{};
	ItemPosition binded_pos{};
};

enum class Currency : unsigned char
{
	GOLD,
	ACHIEVEMENT_POINT,
};

struct PacketSCUpdateCurrency
{
	Currency type{};
	long long value{};
};

enum class PlayerSkillID : unsigned char
{
	NONE,
	ACTIVE_WEAPON_SWORD_MAX_HP,
	ACTIVE_WEAPON_BOW_MAX_HP,

	PASSIVE_WEAPON_SWORD_STRENGTH,

	ACTIVE_COMMON_GHOST,

	PASSIVE_COMMON_LIVELINE,
	PASSIVE_COMMON_MANA_COLLECTOR,
	PASSIVE_COMMON_MONSTER_HUNTER,
	PASSIVE_COMMON_ASSASSIN,
	PASSIVE_COMMON_BRAVERY,
	PASSIVE_COMMON_CONQUEROR,

	PASSIVE_COMMON_BURGLAR,
};

struct PacketSCSkillInfo
{
	PlayerSkillID id{};
	uint16_t level{};
};

enum class Achievement : unsigned char
{
	FIRST_MONSTER_KILLED,
	FIRST_TELEPORT_USED,
};


struct PacketSCAchievementInfo
{
	Achievement id{};
	bool gained{};
};

enum class PlayerStatistic : unsigned char
{
	KILLED_MONSTERS,
	FISHISHED_DUNGEONS,
};

struct PacketSCStatisticInfo
{
	PlayerStatistic id{};
	long long value{};
};

enum class WearType : unsigned char
{
	NONE,
	WEAPON,
	HELMET,
};

struct PacketSCEntergame
{
	char name[24 + 1]{};
	Position pos{};
	float rotation = {};

	//std::array<uint32_t, ecpp::enum_size<WearType>> wear{};
	std::array<uint32_t, 3> wear{};
	WearWeaponMode wear_weapon_mode{};

	std::vector<PacketSCSetAttribute> attributes{};
	std::vector<PacketSCCreateItem> items{};
	std::vector<PacketSCAddToQuickslot> quickslots{};
	std::vector<PacketSCUpdateCurrency> currency{};
	std::vector<PacketSCSkillInfo> skills{};
	std::vector<PacketSCAchievementInfo> achievements{};
	std::vector<PacketSCStatisticInfo> statistics{};
};

namespace godot
{
	struct Array{};
	struct Dictionary {};
}

namespace ecpp
{
	template <typename T, typename ...Other>
	constexpr bool is_any_of_v = (std::is_same_v<T, Other> || ...);
}

template <class T, class TT>
	requires(ecpp::is_any_of_v<TT, godot::Array, godot::Dictionary>)
bool ParseFromPacket(const T& from, TT& to)
{
	auto x = rfl::json::write(from); // <- In main project error happend HERE!!!

	return true;
}

int main()
{
	PacketSCEntergame packet{};
	godot::Array x{};
	for (const auto& item : packet.items)
	{
		ParseFromPacket(item.item_data, x);
	}
    return 0;
}

A quick bugfix for this situation was to comment out 2 lines of a piece of code:

template <class Fields>
constexpr inline bool no_duplicate_field_names() {
  constexpr auto num_fields = rfl::tuple_size_v<Fields>;

  if constexpr (num_fields <= 1) {
    return true;
  } else {
    //no_duplicate_field_names_helpers::iterate_over_i<Fields>( 
    //    std::make_integer_sequence<int, num_fields>());
    return true;
  }
}

or comment last element in enum class Attribute:

enum class Attribute : unsigned char
{
	NONE,

	LEVEL,
	EXP,
	BASIC_ATTRIBUTE_POINT,

	STRENGTHENING_ALL_ATTRIBUTES,

	BASIC_VITALITY,
	VITALITY,
	BASIC_INTELLIGENCE,
	INTELLIGENCE,
	BASIC_STRENGTH,
	STRENGTH,
	BASIC_DEXTERITY, 
	DEXTERITY,
	BASIC_PRECISION, 
	PRECISION,
	BASIC_FOCUS, 
	FOCUS,

	MOVE_SPEED,
	ATTACK_SPEED,

	HEALTH_POINT,
	MAX_HEALTH_POINT,
	MAX_HEALTH_POINT_PERCENT,
	PASSIVE_HEALTH_POINT_REGEN_PER_SECOND,
	ACTIVE_HEALTH_POINT_REGEN_PER_SECOND,
	ACTIVE_HEALTH_REGEN_POINT,

	MANA_POINT,
	MAX_MANA_POINT,
	MAX_MANA_POINT_PERCENT,
	PASSIVE_MANA_POINT_REGEN_PER_SECOND,
	ACTIVE_MANA_POINT_REGEN_PER_SECOND,
	ACTIVE_MANA_REGEN_POINT,

	BASIC_PHYSICAL_ATTACK_DAMAGE,
	MIN_BASIC_PHYSICAL_ATTACK_DAMAGE,
	//MAX_BASIC_PHYSICAL_ATTACK_DAMAGE, <- Without it, the program compiles
};

The value of this element was 33 (if this helps anything)

I understand that this error may be due to a very complex structure and there are limitations here due to the compiler's capabilities, I don't expect the problem to be easy to fix (if at all possible), but I wanted to share my take.

Cheers

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

1 participant