FWorldDelegates Bug

Both FWorldsDelegates::LevelAddedToWorld and FWorldDelegates::LevelRemovedFromWorld are bugged in Standalone releases.

FWorldDelegates::LevelRemovedFromWorld is called “upon loading” the first level (which it never should be). It is never called upon exit unless “more than one” level exist in the same world and even then it is only called for the additional levels.

FWorldDelegates::LevelAddedToWorld is “never” called unless “more than one” level is loaded in. It is never called on the first level.

The steps to reproduce this are rather simple:

  1. Create a new game project and create your own implementation of FDefaultModuleImpl.
  2. Override both StartupModule and ShutdownModule.
  3. In StartupModule use AddRaw to add a callback method to both FWorldDelegates::LevelAddedToWorld and FWorldDelegates::LevelRemovedFromWorld. In my methods, I simply use UE_LOG to make sure the methods were called.
  4. In the shutdown module, simple remove the handles so they’re not lingering. Module shutdown should definitely occur after levels are unloaded, so I assume this isn’t the problem.
  5. Create two levels: one with just a single level and one with world composition.

The single level one will fire “LevelRemovedFromWorld” the second it is loaded and never fire “LevelAddedToWorld.” The world composition level will call “LevelAddedToWorld” and “LevelRemovedFromWorld” for any other level besides the first/persistent level.

UE 4.10.0 officially released right after I started typing this, I will check it to see if it has been fixed, but I doubt it since it probably isn’t something used a lot.

Edit: Bug still persist on 4.10.0

I’ll recreate the set up I had before and upload it to one or the other, thanks . I’ve been trying to track it down myself, but to no avail yet.

Hi zacharymwade,

If you have a sample project demonstrating the issue, would you be able to zip that and upload it to Dropbox or Google Drive? I would like to include that when reporting the issue to make sure your exact setup is used.

Sorry, was running additional test. Okay, when you launch Standalone (from the editor) or package the game, you seem to get the same result. Once the first level is added, RemovedFromWorld is called instantly and passes a nullptr ULevel to all the functions it triggers. If there is only a single level, AddedToWorld will never be called. If there is more than one level, AddedToWorld is called for each additional level. To see the result, just check the “Saved/Logs” for WorldDelegatesLog.

Hi zacharymwade,

Thank you for the sample project. That was very helpful, and showed me exactly what you were describing. I have entered a report about this an attached your project so we can investigate it further (UE-23378).

No problem , always glad to help.

Hi,

Sorry for the delay in replying.

LevelAddedToWorld and LevelRemovedFromWorld are only meant to be called for streaming sub-levels. As such, I’d expect the behavior you describe when loading a non-streaming map (no callbacks) and loading a map with a single single streaming sub-level (level added callback).

To confuse matters though, when a new map is loaded we fire a single call to LevelRemovedFromWorld with NULL for the ULevel*, which signifies that ALL levels have been unloaded, regardless of whether that map contained any streaming sub-levels. This explains the erroneous initial LevelRemovedFromWorld as on initialization we create an empty world in the engine, so that is the one you are getting notified about.

So while some of the behavior might be a little confusing, I don’t believe it is incorrect. We’ve got a ticket open to look at this and try and improve it though!

Thanks for the input!

Graeme

I see, that makes a bit more sense. It does come off as a bit erroneous, but the work around for it was simply to make the persistent level not be a physical level and use a nullptr check. I needed to use the delegates to load/save per-level information. Documentation on some of these systems is so spare, just had to go with what I could deduce, haha. Thanks again.