マルチプレイのSeamlessTravel後のLevelBlueprintやActorのBeginPlay時にGetPlayerControllerが古いPlayerControllerを取得してしまう現象が起きたので内容と対応方法をメモしておきます。
UE4の仕様とかエディタのコードはちゃんと追えてません。
UE4.25.3で確認しました。
発生した現象
OnlineSubsystemを用いたマルチプレイで以下のような関数をサーバーで実行してマップ遷移していた。
bool ATestGameMode::Travel(FString LevelName)
{
bUseSeamlessTravel = true;
return GetWorld()->ServerTravel(LevelName, false, false);
}
以下のようにBeginPlay時にPlayerControllerを取得すると古いものを取得していた。
(GameModeのOnSwapPlayerControllersなどで取得できるPlayerControllerのDisplayNameで一致を確認)
対応したこと
以下のような関数を使うようにして対応。
UFUNCTION(BlueprintPure, Category = MyUtils, meta = (WorldContext="WorldContextObject", UnsafeDuringActorConstruction="true"))
static class APlayerController* GetFirstLocalPlayerController(const UObject* WorldContextObject);
class APlayerController* UMyUtils::GetFirstLocalPlayerController(const UObject* WorldContextObject)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
if (ULocalPlayer* LocalPLayer = World->GetFirstLocalPlayerFromController())
{
return LocalPLayer->GetPlayerController(World);
}
}
return nullptr;
}