The execution order seems to change between Editor and Build which can cause scenarios where you can get an error in PIE In Editor, make a fix, and cause the Build to break.
We have training lessons split up into their own levels and the Level Begin Play interacts with a Widget created by the Player Controller’s Begin Play. In Editor, we receive errors because the Level loads before Player Controller causing NULL values (unless we delay the Level Begin Play in some way).
Since the Level Loads first and I assigned an Event from the Level Blueprint to an Event Dispatcher on the Player Controller called “Ready” for it to call at the end of Begin Play. In the Build, this caused our lesson to break because the Controller loaded first and called “Ready” but the Level had not assigned the Event yet (and there was no way to call the Dispatcher again).
I found a solution that worked for us, but I was curious if there is a particular reason that the Execution Order is different? I didn’t have time to go exploring the Engine code and hoped maybe someone more versed in its construction could explain it to me, or perhaps it was totally unintentional. More info about what I found after testing down below.
I have only been able to test this so far on Windows and In Editor (currently working on testing for Mobile). I also have not been able to test on machines of variable speeds (maybe slower processors would have different results).
Computer Specs (not sure if this is needed but describing my test scenario)
Thanks for that link it explained a little bit, like why Actors in the Level are first in Editor and last in a Build / Standalone. There are a bunch of other unexpected orders too.
Pawn swaps between being “least important” to “most important” (opposite the Actors) which re-organizes Pawn → Player Controller. Player State and Player Controller flip so you can’t rely on Begin Play interactions between those. Level moves from 3rd to nearly last, and nothing can really access the level but can cause broken interactions with the level if it’s assigning events to delegates.
I know you said you can’t answer the why. I’m elaborating in-case someone comes by who could.
Also, for anyone who comes by seeking a solution to this (wanting to remove errors and not break things) my (feels kinda hacky) solution:
Explanation: I added a boolean value so I could test whether or not Begin Play had already completed. If it is true, the level can call the function/event whenever it wants because the Controller should be ready to go. If it is false, the level binds that function/event to a Delegate on the Controller so the controller can tell the Level when it’s done.
I tend to use a single Begin Play in Game Mode, that’s it (apart from dynamically spawned objects, that is). That’s my info hub that sets everything else up, registers some of the main dispatchers, some direct references, spawns helper classes and so on.
BeginPlay is called on creation of actor in play mode just after InitlizeComponents, so what you see is effectivly order of object creation and because Play In Editor is using some hackish world instance swamping order of creation can be different.