Thoughts on uint16 GameplayTagQuery investigation

Hello,

As I mentioned in my [previous [Content removed] we tried converting FGameplayTagQuery::QueryTokenStream from TArray<uint8> to TArray<uint16> to support large queries. Everything worked except in case when the tag query is defined inline inside a BP function. For example by calling `MakeTagQuery` node. By normally I mean that in normal scenario QueryTokenStream would always be properly deserialized and in MakeTagQuery case QueryTokenStream would always be empty.

Our workaround was to change QueryTokenStream to TArray<int32>, which wastes space but does work out of the box

Interestingly uint32 doesn’t work either so it raises a question: what is special with uint8 and int32 that only these types work in this case and why does it only fail when it’s defined inside BP functions. QueryTokenStream is an UPROPERTY but it’s not exposed to BP’s so UHT doesn’t flag it with the error message that type is unsupported.

Interested if you have any insights to share?

---

On the side note, while debugging above we realized that FGameplayTag::Serialize is dead code. Here’s a PR if you’d like to remove it or curious to hear if you have better ideas to do something with it. https://github.com/EpicGames/UnrealEngine/pull/13095

Thanks!

Looking at the PR, I see it is trying to remove FGameplayTagQuery::Serialize, but that function is used by our internal games and probably by licensees as well. The point of Serialize() functions like that is so they can be used from C++ code where the tag query is not used as a UStruct. Most of our types either have a Serialize or an operator<< (it’s inconsistent) so it’s not dead code. I agree that this is confusing, but generally we don’t remove any public functions that could be used by licensees

To your original question, the logic for reading and writing the literal gameplay tag queries that are stored on blueprint pins is handled by SGameplayTagQueryGraphPin. That calls GameplayTagQueryTryImportText and GameplayTagQueryExportText which will call the generic UScriptStruct::Import/ExportText functions. I don’t know why they wouldn’t work properly for your modifications, but it’s possible the int16 versions of those functions are not implemented properly. Int16 is only partially implemented as a property type, but I would have thought it would work for this case.

If you want to keep debugging this, the next step is to use the debugger to walk through ExportText and import text to see what’s going wrong.

Thanks for the details, makes sense.

Side note, for the Serialize to work do you not need `WithSerializer=True`?

template<> struct TStructOpsTypeTraits<FGameplayTagQuery> : public TStructOpsTypeTraitsBase2<FGameplayTagQuery> { enum { WithCopy = true }; };

Thanks for the debugging tips, I’ll take a stab again when I get some free time. Will let you know if I discover anything.

The WithSerializer=True only applies to normal UObject/Property serialization, that tells it to use the native serializer. But even without that you can still just call Serialize() directly from another CPP class’s Serialize(). It’s somewhat faster to use only native serialization but it does NOT handle changes to types very well and will crash without setting up explicit versioning. But if you don’t use that in your project you don’t need to worry about that problem

Gotcha, thank you!