Query regarding noexport and classes with friend structs in Blueprint

So I’ve been working on fixing a bug that occurs when trying to use the autogenerated “Make FRandomStream” node in blueprint. The pull request this question is based on is available here.

Blueprint wants to operate on the UStruct version of FRandomStream defined in Object.h, this is how the original faulty “Make” node was being autogenerated. Because the bug was due to initialization issues, I set a NativeMake function up that would fix the initialization problem. However, it looks like the NativeMake and NativeBreak that I’ve added actually operate on the class version of FRandomStream, defined in RandomStream.h, in the same way that the existing functions like GetRandomFloatFromStream do. My NativeMake function initialises both InitialSeed and Seed, but unless I mark the struct’s version of Seed as a UPROPERTY, by the time I actually try getting a random float from the stream, Seed is back to 0, which was the bug I was trying to fix initially, but InitialSeed is actually set to the value that I had in the NativeMake function. I surmise that this is due to an instance of both class and struct being created, but have no idea why you’d need that to happen.

My questions are these:

  1. Why is it necessary to have both a struct and a class called FRandomStream, and how do they relate to each other? I can see that the class has a function which is autogenerated from the struct definition as a friend, but there’s no real explanation for this pattern, which I’ve also seen with some other types like FTransform.

  2. It looks as though data is being somehow synchronised between the class and the struct, because the struct is still being initialised with InitialSeed from the class. How is this being accomplished? I could see Z_Construct_UScriptStruct_UObject_FRandomStream in the autogenerated code, which is the aforementioned friend function, but given it’s not really intended for human consumption the generated code was not of much assistance.

  3. Why do I need to mark Seed as a UPROPERTY in the struct in order for the synchronisation to work, considering that ‘noexport’ is supposed to indicate that the struct is only used for metadata, and I’m only adding a blank UProperty tag to Seed, with no metadata?

Hey-

It appears that the pull request you mentioned has been incorporated into the engine (https://github.com/EpicGames/UnrealEngine/commit/8c490369bc0c6dff1d802f912aff1e6611dde621). Are you still experiencing this problem after adding this commit to your version of the engine? Let us know if you have any other questions regarding the FRandomStream node or the pull request.

Cheers

Hi,

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will offer further assistance.

Thank you.

Hi ,
I don’t get notifications to comments on questions for some reason, so I only just saw your message.
The PR has been integrated, and all is well from that perspective, but I do think it would be useful to formally document a bit more information regarding the use of a class and mirrored struct - I believe it is a pattern that you no longer implement in the engine yourselves, but there’s quite a number of core classes that still use the pattern as they are, and so it would be helpful for people to understand why that was implemented in that fashion, and how the struct and class interrelate. Whether this question, or a page in the API documentation, is the best place to situate that information I leave to you.

Hey-

I have submitted your request for more thorough documentation regarding class usage and mirrored structs for further review by developers.