I am still new to Unreal Engine (5.3) and it’s C++ API, but I am comfortable with C++ in general. I have started on game saving and loading fairly early in things in order to understand a lot of the object relationships sooner instead of retrofitting to them later. I found inspiration for how I wanted to save and load games from this post:
It is saving off actors and replacing the ones in the level with the saved ones on reload.
I am having a problem with loading the player. I don’t get the old player, but instead get a default one at the default player start as if starting a new game. Some important things that are involved:
- A custom game mode I am using for trying different overrides. This is just for testing and wasn’t even there until I saw this problem.
- A BP_ThirdPersonGameMode I have set to be use my custom game mode as a parent. I do see my overrides run. So both my project and world settings properly use this game mode chain-of-command.
- The save-load logic itself.
- A level loading call. Specifically:
UGameplayStatics::OpenLevel(GetWorld(), TEXT("/Game/IntroLevel"), TRAVEL_Absolute);
. I bring it up because I see something likeLogLoad: Took 0.041540 seconds to LoadMap(/Game/UEDPIE_0_IntroLevel)
as the last message I get so I wouldn’t be surprised if there’s some hidden sauce that OpenLevel does to make things interesting.
The current situation when I opt to load a game:
- I note the current player’s actor GUID in the editor. Let’s say it is AAAA.
- I activate my code to load from a save. This starts with the OpenLevel call
UGameplayStatics::OpenLevel(GetWorld(), TEXT("/Game/IntroLevel"), TRAVEL_Absolute);
- I load the game state I want and create a new player actor reconstructed from the save data. I should note in particular that I have a player transform here. I have seen this code run.
- I then possess the new actor after casting it to a pawn. I should note here that when I scan for all instances of APawn in this code, I get two. First, there is the original one with guid AAAA that has been marked to be destroyed. I guess it isn’t destroyed yet and still comes up. I then get a second one. Let us give it guid BBBB. This is the one I possess.
- I note in the editor that the player pawn has been moved to the Player Start, not the location where I wanted it to be. Furthermore, my player has a third, new guid of CCCC that I didn’t see when loading. So it looks like I’m generating a completely new one. I also don’t have control over it.
This is where I start to inject an overridden AGameModeBase to try to have some agency over the pawn logic. I tried to override RestartPlayer() to call the base call just once using a bool. So after calling it once, it’ll set a boolean to true and then suppress calling it again. This didn’t change the behavior. I then decided to set DefaultPawnClass to nullptr in the same block that sets the boolean. That didn’t change anything. Now, if I completely suppress RestartPlayer, then I wind up with some 1st-person floating viewport, so it’s clear this function does do something overall. I just can’t tell what exactly.
I searched the forums for other things I could override in AGameModeBase, but a few of them are no longer virtual functions. For example: SpawnDefaultPawnFor, SpawnDefaultPawnAtTransform, PlayerCanRestart. I don’t get why because they are native events so I figure in Blueprint you could try to mess with them (and I might!). But I figured I’ve done my due diligence at this point and I can just ask.