Keywords: UE4, Networking, Dedicated Server,ClientTravel, ServerTravel, UEngine::Browse


Difference between ServerTravel and ClientTravel
  • ServerTravel also informs the clients to move along with the server.
  • ClientTravel will be called locally for the client to load a new map. or connect to ip.
  • Browse can load local map via LoadMap ( not for multiplayer ) but there are more things happening in this method. I also want to know more about what it does and what it should be used for.
  • LoadMap should also load a map for a local client

Browse, LoadMap, ServerTravel and ClientTravel?

What’s the different between absolute travel and relative travel?

What is the difference between ServerTravel and OpenLevel?

PlayerController->ClientTravel() (Connect to remote server)

Seamless and non-seamless travel


How to pass arguments from Client to Server

When execute PlayerController->ClientTravel, default URL is like this:

FString Address = TEXT("");

If want to pass arguments to Server when logining, URL format is like this:

FString Address = FString::Printf(TEXT(""), *Param1, *Param2);
How to parse arguments sent by Client on Server

Overrice function InitNewPlayer() in GameMode, then parse arguments like this:

FString AMyGameMode::InitNewPlayer(APlayerController* NewPlayerController, const FUniqueNetIdRepl& UniqueId, const FString& Options, const FString& Portal = TEXT(""))
    FString Param1 = UGameplayStatics::ParseOption(Options, TEXT("Param1"));
    FString Param2 = UGameplayStatics::ParseOption(Options, TEXT("Param2"));

Official Doc: Passing Arguments To Server During Connection

How does Server informs Clients which are connected to Server to travel map

Execute ClientTravel on Server:

void AMyGameModeBase::PostLogin(APlayerController* NewPlayer)
    FString URL = TEXT("/Game/Maps/TestMap");
    NewPlayer->ClientTravel(URL, TRAVEL_Absolute);

This way works right for travelling to new map, but Client would also disconnect to Server. It means that the NetMode of all Actors in Client would be set as NM_Standalone.

How to use ServerTravel

A common use case is starting a server in a lobby level. Clients connect to this lobby level and choose loadout and character, for example. When ready, the server triggers a ServerTravel, which transitions all clients into the main game level.

When ServerTravel is triggered, the server tells all clients to begin to ClientTravel to the map specified. If the ServerTravel is seamless then the client maintains its connection to the server. If it’s not seamless then all the clients disconnect from the server and reconnect once they have loaded the map. Internally, the server does a similar process: it loads in the new level, usually a game world for all the clients to play on, and begins accepting player spawn requests once ready.

Reference: Map travel

Enabling Seamless Travel

To enable seamless travel, you need to setup a transition map. This is configured through the UGameMapsSettings::TransitionMap property. By default this property is empty, and if your game leaves this property empty, an empty map will be created for the transition map.

The reason the transition map exists, is that there must always be a world loaded (which holds the map), so we can’t free the old map before loading the new one. Since maps can be very large, it would be a bad idea to have the old and new map in memory at the same time, so this is where the transition map comes in.

So now we can travel from the current map to the transition map, and then from there we can travel to the final map. Since the transition map is very small, it doesn’t add much extra overhead while it overlaps the current and final map.

Once you have the transition map setup, you set AGameModeBase::bUseSeamlessTravel to true, and from there seamless travel should work!



See the usage of APlayerController->ClientTravel() in offical example Shooter Game.

Seamless travel

After seamless travel AGameModeBase::GenericPlayerInitialization(AController* Controller) and AGameModeBase::HandleStartingNewPlayer(), Gets called for the client.


Travelling API in GameMode


APlayerController* AGameModeBase::ProcessClientTravel(FString& FURL, FGuid NextMapGuid, bool bSeamless, bool bAbsolute)
    // We call PreClientTravel directly on any local PlayerPawns (ie listen server)
    APlayerController* LocalPlayerController = nullptr;
    for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
        if (APlayerController* PlayerController = Iterator->Get())
            if (Cast<UNetConnection>(PlayerController->Player) != nullptr)
                // Remote player
                PlayerController->ClientTravel(FURL, TRAVEL_Relative, bSeamless, NextMapGuid);
                // Local player
                LocalPlayerController = PlayerController;
                PlayerController->PreClientTravel(FURL, bAbsolute ? TRAVEL_Absolute : TRAVEL_Relative, bSeamless);

    return LocalPlayerController;


void AGameModeBase::ProcessServerTravel(const FString& URL, bool bAbsolute)

    // Force an old style load screen if the server has been up for a long time so that TimeSeconds doesn't overflow and break everything
    bool bSeamless = (bUseSeamlessTravel && GetWorld()->TimeSeconds < 172800.0f); // 172800 seconds == 48 hours

    FString NextMap;
    if (URL.ToUpper().Contains(TEXT("?RESTART")))
        NextMap = UWorld::RemovePIEPrefix(GetOutermost()->GetName());
        int32 OptionStart = URL.Find(TEXT("?"));
        if (OptionStart == INDEX_NONE)
            NextMap = URL;
            NextMap = URL.Left(OptionStart);

    FGuid NextMapGuid = UEngine::GetPackageGuid(FName(*NextMap), GetWorld()->IsPlayInEditor());

    // Notify clients we're switching level and give them time to receive.
    FString URLMod = URL;
    APlayerController* LocalPlayer = ProcessClientTravel(URLMod, NextMapGuid, bSeamless, bAbsolute);

    UE_LOG(LogGameMode, Log, TEXT("ProcessServerTravel: %s"), *URL);
    UWorld* World = GetWorld();
    World->NextURL = URL;
    ENetMode NetMode = GetNetMode();

    if (bSeamless)
        World->SeamlessTravel(World->NextURL, bAbsolute);
        World->NextURL = TEXT("");
    // Switch immediately if not networking.
    else if (NetMode != NM_DedicatedServer && NetMode != NM_ListenServer)
        World->NextSwitchCountdown = 0.0f;


Official Docs

Travelling in Multiplayer