Both FName
and FGameplayTag
fill your requirements.
Ignoring FGameplayTag
“for perf reasons” likely stems from a misunderstanding of how it works - gameplay tags aren’t strings, they’re backed by FName
with some extra functionality. And names are stored as an index into a global table of strings. Comparing names is quick as you’re comparing indices into that table, not iterating strings. Hashing and just about every other operation is the same way up until you need to do real string operations on them (which involves getting a real string rather than doing anything with the name/gameplay tag, but this isn’t any slower than what you’d need to do with an enum anyway).
Initial creation of names from strings is slow (relative to simply assigning an enum value), but you can either use gameplay tags (which must be defined by engine startup and shouldn’t be created or looked up at runtime if you can help it) or reference static instances of names from code. So you should really only have to pay that cost on startup.
If you really want something based on actual enums it’d be possible to wrap your enums with a custom USTRUCT
that has its own serialization/deserialization methods. You’d need to make a wrapper for every enum you want to work this way, however.
Some further reading:
- General gameplay tag docs - Gameplay Tags | Unreal Engine 4.27 Documentation
- Defining gameplay tags from C++ - Native Gameplay Tags (New in 4.27 and UE5) – The Games Dev
- FName docs - FName | Unreal Engine Documentation