Crossplay Integration Kit
Multiplayer

Host migration in C++

Drive or extend host migration from C++ with the subsystem, the state component and the snapshot utilities

Host migration in C++

Everything the nodes do lives on UUCIKHostMigrationSubsystem (HostMigration/UCIKHostMigrationSubsystem.h), a game-instance subsystem that survives the world the host took down.

UUCIKHostMigrationSubsystem* Migration = GetGameInstance()->GetSubsystem<UUCIKHostMigrationSubsystem>();

Migration->OnHostElectedNative.AddUObject(this, &UMyGameInstance::HandleHostElected);

void UMyGameInstance::HandleHostElected(const FUCIK_MigrationContext& Context)
{
	if (Context.bLocalIsElected)
	{
		Migration->BecomeHost(FString(), FUCIKCallback<FUCIK_ConnectInfo>::CreateWeakLambda(this, [](const TUCIKResult<FUCIK_ConnectInfo>& Result) { /* hosting */ }));
		return;
	}
	Migration->WaitForHost(0.0f, FUCIKCallback<FString>::CreateWeakLambda(this, [this](const TUCIKResult<FString>& Result)
		{
			if (Result.bOk)
			{
				Migration->ReconnectToHost(FUCIKCallback<bool>());
			}
		}));
}

RunMigration() does exactly that sequence, and Seamless mode calls it for you. HandOverHost(Preferred, Callback) promotes another member before the current host leaves. AbortMigration(Error) stops everything. GetPhase(), GetContext(), GetCandidates(), GetPeers() and GetLastSeenEpoch() expose the state; every dynamic event has a ...Native twin.

Events and providers

The lobby and session provider contracts carry what migration needs:

  • FUCIKLobbyProviderEvents::OnMemberLeft delivers FUCIK_MemberLeftEvent with Reason (EUCIK_LeaveReason) and bWasOwner; OnOwnerChanged delivers FUCIK_OwnerChangedEvent with PreviousOwner and bLocalIsNewOwner. UUCIK_LobbyEventsSubsystem fills the previous owner and owner flag from the owner it recorded, so providers only report what they know.
  • EUCIK_LobbyCapability::NativeHostElection (EOS, Steam) tells the subsystem to wait for the service's owner change; otherwise it ranks members (UCIKHostMigrationUtilities::RankCandidates / ElectHost).
  • IUCIKSessionProvider gained RegisterEvents, PromoteMember, SetSessionAttributes, GetSessionAttributes and QueryMembers behind the Events, Promote and Attributes capabilities; UUCIK_SessionEventsSubsystem fans them out.
  • IUCIKLobbyProvider::ClearHostAddress removes any explicit host address the old owner published (Steam's GameServer* keys) so the connect string resolves to the current owner again.

Announcements are plain attributes: UCIKHostMigrationUtilities::MakeClaim, MakeReady and ParseAnnouncement read and write UCIK_MigrationEpoch, UCIK_MigrationState, UCIK_MigrationHost, UCIK_HostHandle and UCIK_ConnectString.

Peers

On a listen server UCIK adds UUCIKPeerListComponent to the game state and UUCIKPlayerLinkComponent to every player controller. The link reports the client's UCIK handles to the host; the peer list replicates handle, ping, join order, player id and (Direct IP) address to everyone. RegisterPeer(Handle, Address) sets the address the game knows; the host publishes per-member UCIK_Ping_<handle> and UCIK_JoinOrder_<handle> lobby attributes so members can rank each other later.

Seamless state

UUCIKMigrationStateComponent marks an actor for capture. UCIKWorldSnapshotUtilities::Capture walks tagged actors and player states into an FUCIK_WorldSnapshot; Restore matches placed actors by id, spawns missing ones deferred, applies transform, velocity and SaveGame properties, then re-links references. References to tagged actors are written as ucik-mig:<guid>[/<component>] by FUCIKMigrationWriter and resolved by FUCIKMigrationReader; other object references are written as paths, so assets and CDOs round-trip and untagged runtime actors become null.

The subsystem captures on a timer on clients (SnapshotIntervalSeconds) and inside GEngine->OnNetworkFailure() before the engine tears the world down, restores on the new host at FWorldDelegates::OnWorldInitializedActors, and finishes each returning player when its link reports (OnPlayerRestored). Override OnBeforeCapture / OnAfterRestore on the component to hook the game's own bookkeeping.

Test seams: SetTravelDriver(TSharedPtr<IUCIKTravelDriver>) replaces listen-server hosting and travel; IngestHostLost, IngestOwnerElected, IngestAnnouncement and IngestPeers feed events without a service. See Source/UCIKCore/Private/Tests/UCIKHostMigrationTests.cpp and UCIKSnapshotTests.cpp.

On this page