Is order of RPCs and property replication guaranteed between actors? Is it different with Iris?

I’m working on migration to Iris and found a peculiar problem. We have Widgets in the AHUD which initialize a cached HUD variable from APlayerController on NativeConstruct. With traditional replication it works fine, the order is as follows:

  • APlayerController::ClientSetHUD RPC comes in, APlayerController creates HUD, but doesn’t initialize widgets, since the OnRep_ReplicatedHasBegunPlay hasn’t come yet so no BeginPlays.
  • OnRep_ReplicatedHasBegunPlay comes in, BeginPlays are dispatched
  • In BeginPlay of AHUD widgets initialize and can retrieve the pointer to HUD from APlayerController

But with Iris I have non-100% repro where sometimes these come in a different order like this:

  • OnRep_ReplicatedHasBegunPlay comes in first
  • APlayerController::ClientSetHUD RPC comes second and while creating HUD it also runs BeginPlay and initializes widgets, which try to retrieve HUD from PlayerController, but can’t - we’re in the middle of AHUD creation!
  • Widgets end up without HUD and misbehave until we refresh the UI manually.

Creation of HUD happens in APlayerController::ClientSetHUD_Implementation:

MyHUD = GetWorld()->SpawnActor<AHUD>(NewHUDClass, SpawnInfo );

This happens during SeamlessTravel to the server I see the following snippet of code in FSeamlessTravelHandler::Tick at the very end:

AGameModeBase* const GameMode = LoadedWorld->GetAuthGameMode();
if (GameMode)
{
	// inform the new GameMode so it can handle players that persisted
	GameMode->PostSeamlessTravel();					
}

// Called after post seamless travel to make sure players are setup correctly first
LoadedWorld->BeginPlay();

PostSeamlessTravel is the one that sends APlayerController::ClientSetHUD RPC and BeginPlay is the one that sets the replicated begin play which has OnRep_ReplicatedHasBegunPlay RepNotify. So it seems like it is meant to first all the player/HUD setup and only then perform BeginPlays.

In the docs (Replicated Object Execution Order in Unreal Engine | Unreal Engine 5.6 Documentation | Epic Developer Community) it says that replicated properties indeed come after RPCs, but it is not clear if this only holds true for a single actor or between actors also. In this case we have an RPC for APlayerController and property for AGameModeBase, which are different actors.

If replication order should be guaranteed here, then Iris seems to break this guarantee. If not - then I suppose our widgets should not try to get HUD during construction, since it can happen during HUDs own construction. Also the seamless travel comment then must be misleading, since players would not necessarily have the time to be setup first. Could someone clarify?

EDIT: Actually on the second thought I’m not sure how not to use HUD here since we need data it has during initial widget setup.