SunMoonDaySequence actor loading asserts with Debug Binary Config

We have a SunMoonDaySequence actor in our entry map and it results in loading assertions when we launch the game with a debug bin.

The problem occurs on cooked builds. Not on uncooked nor packaged builds.

Could use some advice on how to resolve the problem.

Steps to Reproduce

Have a SunMoonDaySequence actor in a map.

Launch standalone (cooked build) game with debug bin with that map as first map to be loaded into.

Upon loading of that map this assertion should hit:

`Assertion failed: IsInGameThread() [File:D:\SVNs\CGUE\Engine\Source\Runtime\CoreUObject\Private\Serialization\AsyncLoading.cpp] [Line: 7453]
LoadPackageAsync is only thread-safe when using the zenloader (i.e. AsyncLoading2).

DOE_Win64_DebugGame!FAsyncLoadingThread::LoadPackage()
DOE_Win64_DebugGame!FAsyncLoadingThread::LoadPackage()
DOE_Win64_DebugGame!LoadPackageAsync()
DOE_Win64_DebugGame!LoadPackageInternal()
DOE_Win64_DebugGame!LoadPackage()
DOE_Win64_DebugGame!LoadPackage()
DOE_Win64_DebugGame!ResolveName2()
DOE_Win64_DebugGame!StaticLoadObjectInternal()
DOE_Win64_DebugGame!StaticLoadObject()
DOE_Win64_DebugGame!ConstructorHelpersInternal::FindOrLoadObject()
DOE_Win64_DebugGame!ASunMoonDaySequenceActor::ASunMoonDaySequenceActor()
DOE_Win64_DebugGame!StaticConstructObject_Internal()
DOE_Win64_DebugGame!FAsyncPackage::EventDrivenCreateExport()
DOE_Win64_DebugGame!FAsyncPackage::ProcessImportsAndExports_Event()
DOE_Win64_DebugGame!FAsyncPackage::Event_ProcessImportsAndExports()
DOE_Win64_DebugGame!UObjectBaseUtility::GetStatID'::2’::<lambda_1>::operator()()
DOE_Win64_DebugGame!FAsyncLoadingThread::ProcessAsyncLoading()
DOE_Win64_DebugGame!FAsyncLoadingThread::TickAsyncThread()
DOE_Win64_DebugGame!FAsyncLoadingThread::Run()
DOE_Win64_DebugGame!FRunnableThreadWin::Run()`

Hi,

looking at the error message, it seems you are still using the old event driven loader instead of the new zenloader.

Are you packaging the cooked build with loose files (i.e. not using pak/iostore files)?

Or cooking from the Editor/UBT and launching from Visual Studio in the DebugGame configuration?

A build that loads loose cooked files from disk is the only configuration that still uses the old loader and we consider that path deprecated.

To fix this specific issue you could try enabling the “Use Zen Server as cooked output store” option in the project’s packaging settings.

This should store the cooked files in zen server and use the new loader, which allows this type of loading to succeed.

Zen loader is the default for recent Unreal versions and should fix this specific issue (plus the zen loader is more performant overall).

An alternative route could be to try out setting the following cvar to disable async loading during level load.

This could force the actor to be loaded on the game thread and should avoid that specific issue, at a performance cost for level loading in general:

s.World.ForceFlushAllAsyncLoadsDuringLevelStreaming 1This is likely not a good idea for runtime performance but if this fixes the crash it would confirm my suspicion that this is caused by the new async loading functionality during level streaming.

Let me know if any of these help!

Best,

Sebastian

> “we consider that path deprecated.” eh, is this mentioned anywhere else?

Not officially yet, apologies for the alarming wording.

To be more specific: The old loading path is successively being removed in favor of zen loader, and will be deprecated and removed after all use cases are covered by zen loader. This is mostly an internal change and other than issues like the one you’re seeing it should be transparent to users.

This does not affect the ability to run from visual studio in any way.

Loading cooked assets from loose files is one of the last use-cases in 5.5 that still uses the old loader.

Loading from loose cooked files is also not deprecated, but we are moving towards a new with Zen as cooked Output store.

Eventually we also want to get away from the loose files workflow, but since the Zen Store approach for that is beta in 5.5 using loose cooked files is still fully supported.

However, since most use-cases (i.e. Editor and packaged game with pak/iostore files) don’t use the old loader anymore it is sees a lot less usage and testing nowadays, which is probably the reason why the DaySequence plugin breaks in combination with the also quite recent async level loading.

> s.World.ForceFlushAllAsyncLoadsDuringLevelStreaming 1 : had no effect on the problem

> cook.skipasyncloaderforcookeddata 1 : did have an effect, avoided the assertion but then gets stuck in infinite wait event loop

Thanks for trying the cvars. It was a bit of a guess so we’ll explore other options.

> bUseZenStore true : had an effect, but a pop up window appears saying it failed to connect to zen server.

The editor or game should be able to start the zen server on-demand if it is required.

Could you run the Zen Dashboard from Engine\Binaries\Win64\ZenDashboard.exe and start the server manually from Tools > Start Zen Server please?

[Image Removed]

You’ll also need to cook at least once with the option enabled to make sure all the cooked data is actually stored inside the Zen Storage.

If it works as expected with that done I’d recommend this workflow for now, since Zen as cooked output store will be production ready in 5.6 and the default in future versions.

> When I turned bUseZenStore back off, cooked again, tested again, the pop up was still happening, as if the cooker was not removing the zen state on things.

I think this is actually a bug on our side and I will forward this to the respective team.

When this option is enabled instead of saving the loose files only a ue.projectstore file will be stored in Saved/Cooked/Windows/, to let the game know it should try to load from the zenserver instead.

I believe disabling this option might not delete the respective file. You should be able to delete the file from the “Cooked” folder to restore the old behavior.

Please make sure to recook after changing that option, too.

Edit: I’ve tested this in both 5.5 and 5.6 and could not reproduce a case where the projectstore file was still present even after recooking. Not sure why this didn’t work for you in this case.

Best,

Sebastian

Yes, in this case the error is not fatal anymore and you can ignore it for now.

I’ll talk to the DaySequence developers to improve the setup here, using ConstructorHelpers to load assets from the CDO is something we’re trying to avoid in general.

The problem with the ConstructorHelpers is that they force a synchronous load, which is generally only save from the game thread.

In this case the second load inside the if is actually happening later when the actors from the map are async loaded, so it’s not on the gamethread anymore.

A better approach is to use an async load instead in the constructor, e.g. by using LoadPackageAsync() or StreamableManager::RequestAsyncLoad() with a lambda callback or polling the StreamableHandle.

Then at runtime when the load finishes the DaySequenceCollection member should be set to the new texture.

Another option would be to use a soft reference like TSoftObjectPtr<> to store the texture reference and then load it in beginplay or at runtime on-demand.

P.S. Looking at your last sentence it’s actually a bit simpler, just moving the lines outside of the if (!IsTemplate()) should force the load to happen during early engine init and thus on the game thread.

It’s still not optimal (because it will always be force loaded, regardless of if any actor actually exists in the world) but it’s probably the easiest fix.

Edit: I’ve tested this locally and just commenting out the if and keeping it’s contents should be fine as a workaround for now.

Hi,

Thanks for the quick response.

Yes it was cook from editor with default config, UsePakFile true, bUseIOStore true, bUseZenStore false.

Yes launch from vis studio with debuggame or development configs.

“we consider that path deprecated.” eh, is this mentioned anywhere else?

Ok I tried the following:

  1. s.World.ForceFlushAllAsyncLoadsDuringLevelStreaming 1 : had no effect on the problem
  2. cook.skipasyncloaderforcookeddata 1 : did have an effect, avoided the assertion but then gets stuck in infinite wait event loop
  3. bUseZenStore true : had an effect, but a pop up window appears saying it failed to connect to zen server. (is that required to have now?, I just need a local setup for quick testing) It also said “you can use installed build without network streaming by building with the -pak argument.” But UsePakFile was already true…

When I turned bUseZenStore back off, cooked again, tested again, the pop up was still happening, as if the cooker was not removing the zen state on things.

Ok I set the config to have those three options true (usepak, useiostore, usezenstore), I checked the zen launcher and confirmed that the zenserver is running and that it has the path to the local ddc. I recooked.

I try launching the game with dev game binary config, and it doesn’t hit the same assert as before instead it hits this one but still related to the sunmoondaysequence actor (see attached log file).

“using ConstructorHelpers to load assets from the CDO is something we’re trying to avoid in general.”

What would be the recommended alternative to that, I think we just want to fix this locally for now to minimize the hassle.

Like I see it only does one of them if its not template but I thought that was also the one it was asserting on.

hmm I did test that but that was when I wasn’t using the zenloader so it was hitting other asserts.

Anyways thanks for the help!