x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

How can I execute code immediately after loading a non-streaming level?

I'm working on Save/Load game code, and to load the level, I use GameplayStatics::LoadLevel(), and then set actor positions around the level to where they were saved at.

The problem is, LoadLevel() seems to only set some flags, and then the level is actually loaded on the next tick. There isn't any callback functions for when it actually is loaded.

I might be able to do this by using streaming levels, but there appears to be no way to open a level that wasn't already put into the persistent world by the editor. Plus, I'm using world composition as well, which may complicate that idea.

How can I get some code to run immediately after loading another level, without having to put a myriad of checks and flags in each level?

Product Version: UE 4.8
Tags:
more ▼

asked Mar 22 '16 at 05:11 AM in C++ Programming

avatar image

Willtheoct
33 13 14 16

avatar image Willtheoct Mar 22 '16 at 05:16 AM

Some code, in case the above wasn't clear enough: NameOf() is a helper function returning an FString, LoadedLevelNames[] and SavedPawnList[] are TArrays loaded from SaveGame:

 void UMySaveGame::LoadLevels(UWorld* TheWorld)
 {
     UE_LOG(GameInfo, Log, TEXT("Loading..."));
 
     //load level
     //UGameplayStatics::LoadGameFromSlot();
     for (int i = 0; i < LoadedLevelNames.Num(); ++i)
     {
         UE_LOG(GameInfo, Log, TEXT("Level: %s"), *LoadedLevelNames[i]);
         UGameplayStatics::OpenLevel(TheWorld, FName(*LoadedLevelNames[i]),false);
     }
 
     //loop through spawn things
     TArray<AActor*> actorlist = TheWorld->GetCurrentLevel()->Actors;
     for (int i = 0; i < actorlist.Num(); ++i)
     {
         APawn* ThePawn = Cast<APawn>(actorlist[i]);
         if (ThePawn != nullptr)
         {
             UE_LOG(GameInfo, Log, TEXT("Loading pawn #%i. name: %s"), i, *NameOf(ThePawn));
             UE_LOG(GameInfo, Log, TEXT("Saved pawn list has #%i entries."), SavedPawnList.Num());
             for (int j = 0; j < SavedPawnList.Num(); ++j)
             {
                 FSavedPawn sp = SavedPawnList[j];
                 UE_LOG(GameInfo, Log, TEXT("Checking against saved pawn with name: "), i, *NameOf(sp));
                 if (NameOf(ThePawn).Equals(NameOf(sp)))
                 {
                     UE_LOG(GameInfo, Log, TEXT("Pawn #%i, %s was found and will be loaded."), i, *NameOf(ThePawn));
                     ThePawn->SetActorLocationAndRotation(sp.Position, sp.Rotation, false);
 
                     //quick remove of saved pawn from list, so it will not turn up in future searches. Safely reorder because we're returning afterwards.
                     SavedPawnList.RemoveAtSwap(j, 1);
                     return;
                 }
             }
         }
     }
 
     //execute BP
     Load_Event();
 }
avatar image Shadowriver Mar 22 '16 at 03:36 PM

Did you tried to using default UE4 save system?

avatar image Willtheoct Mar 22 '16 at 03:53 PM

If you mean SaveGames, then yes, that's what's in use here. The problem is, the actor positions are (trying to be) set in this load code, but then the level is loaded on the next tick, which effectively makes the load code useless.

I need to run the loading code -after- the level has loaded, and I'm not sure how to do that.

avatar image Willtheoct Mar 25 '16 at 02:42 AM

So far, I've been looking into UE4's level and world delegates, but with no success. It seems the delegates are members of a UWorld, and the UWorld is destroyed on level load. I've tried adding:

     TheWorld->OnLevelsChanged().AddUObject(this, &UMySaveGame::PostLevelLoad);


and:

     FCoreUObjectDelegates::PostLoadMap.AddUObject(this, &UMySaveGame::PostLevelLoad);


but PostLevelLoad() is never a part of either delegates' invocation lists when the level changes and the delegates are called.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

3 answers: sort voted first

My solution was to set a static flag, and since my game has only one game mode, I can override its GenericPlayerInitialization(AController* C) function to run my game load code after the level changes.

This is a terrible, terrible hack and still gets called before a pawn spawns from a "player start" placed in the level. Hopefully Epic can add a delegate somewhere that gets called after the level is fully loaded.

There are even a few of these delegates in code, but none are actually called, and are pretty misleading.

more ▼

answered Apr 02 '16 at 09:00 PM

avatar image

Willtheoct
33 13 14 16

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Old post, I know, but I've been working on this exact issue the last few days.

My solution was to create a custom ALevelScriptActor for any level I want to be saveable. Override BeginPlay, then after Super::BeginPlay(), put your loading code.

Still feels very hacky, but the player controller & pawn are spawned, would work across multiple game modes etc.

more ▼

answered Jun 17 '16 at 02:21 PM

avatar image

sqwyd
1 1

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Resurrecting this post with another solution since Google brought me to this topic.

All you need to do is override GameInstance::LoadComplete(const float, const FString&). This one will get called reliably since GameInstance persists over level loads.

Personally I think this is a clean solution. Tested in UE4.22

more ▼

answered Jul 08 '19 at 09:13 PM

avatar image

Jasdela
21 4

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question