Network Error force loads Entry map for client when server shuts down

This seems to have been an issue for some time now without being resolved.
If a listen server disconnects, the connected client in the session will get a Network Error event and is then loaded into Entry, regardless if that Network Error event is connected to a Open Level or console command (open mapname) these will be ignored and the client will end up on the Entry map.

I can’t find any way of fixing this and it is a problem. Any advice is appreciated!

2 Likes

Did you ever find a solution to this?

Not really, I did some hacky fix by setting a bool when the network error occurs, and if that bool is set when the entry map loads, it instantly loads the menu map, error messages etc. It works tho.

1 Like

yeah, I actually did similar, not happy about it though. I have it that on network error, I quickly load the main menu (from the entry map Splash screen), and show an error message. Not so pretty.

guys, seems like this is the only solution, even if we don’t like it. i checked ShooterGame example, and they do the same, after disconnect they change GameState to ErrorMessage, and game opens default level, then this game state value is applied

While I’m sure there’s better ways, this seemed to do the trick for me.

void HandleNetworkFailure(UWorld* World, UNetDriver* NetDriver, ENetworkFailure::Type FailureType, const FString& ErrorString);

HandleNetworkFailure is found in the UnrealEngine.h file and can be overridden - this has other interesting stuff like OnTravelFailure.

void UMyGameInstance::HandleNetworkFailure(UWorld* World, UNetDriver* NetDriver, ENetworkFailure::Type FailureType, const FString& ErrorString) {
	if (FailureType == ENetworkFailure::FailureReceived || FailureType == ENetworkFailure::ConnectionLost) {
		APlayerController* PlayerController = GetFirstLocalPlayerController();
		if (!ensure(PlayerController != nullptr)) return;

		PlayerController->ClientTravel("/Game/Maps/MainMenu", ETravelType::TRAVEL_Absolute);
	}
}

The function can be implemented as shown above. Running multiple instances via commandline with log reveiled the FailureType to be FailureReceived and ConnectionLost so do a check - eventually it’ll be caught and you can do a client travel to the main menu.

	GetEngine()->OnNetworkFailure().AddUObject(this, &UMyGameInstance::HandleNetworkFailure);

Lastly, add a delegate with the function to the OnNetworkFailure event in the Init function of your GameInstance, or where you prefer, and it should be working.

1 Like

I’ve also implemented your solution, but I still cannot control clientTraveling to the EntryMap. I don’t want the client to travel anywhere.
How do you choose whether/where the client will travel to post-NetworkError?

1 Like

UGameMapsSettings::SetGameDefaultMap(levelName);

Funny, I implemented the exact same solution and found this topic after -_-

It raises a 'package not found' error… If set default map to None

found.

void UEngine::HandleDisconnect( UWorld *InWorld, UNetDriver *NetDriver )
{
	// There must be some context for this disconnect
	check(InWorld || NetDriver);

	// InWorld might be null. It might also not map to any valid world context (for example, a pending net game disconnect)
	// If there is a context for this world, setup client travel.
	if (FWorldContext* WorldContext = GetWorldContextFromWorld(InWorld))
	{
		// Remove ?Listen parameter, if it exists
		WorldContext->LastURL.RemoveOption( TEXT("Listen") );
		WorldContext->LastURL.RemoveOption( TEXT("LAN") );

		// Net driver destruction will occur during LoadMap (prevents GetNetMode from changing output for the remainder of the frame)
		// The ?closed option will also make sure any PendingNetGame is cancelled in Browse
		SetClientTravel( InWorld, TEXT("?closed"), TRAVEL_Absolute );
	}
	else if (NetDriver)
	{
		// If the NetDriver that failed was a pending netgame driver, cancel the PendingNetGame
		CancelPending(NetDriver);

		// Shut down any existing game connections
		if (InWorld)
		{
			// Call this to remove the NetDriver from the world context's ActiveNetDriver list
			DestroyNamedNetDriver(InWorld, NetDriver->NetDriverName);
		}
		else
		{
			NetDriver->Shutdown();
			NetDriver->LowLevelDestroy();

			// In this case, the world is null and something went wrong, so we should travel back to the default world so that we
			// can get back to a good state.
			for (FWorldContext& PotentialWorldContext : WorldList)
			{
				if (PotentialWorldContext.WorldType == EWorldType::Game)
				{
					FURL DefaultURL;
					DefaultURL.LoadURLConfig(TEXT("DefaultPlayer"), GGameIni);
					const UGameMapsSettings* GameMapsSettings = GetDefault<UGameMapsSettings>();
					if (GameMapsSettings)
					{
						PotentialWorldContext.TravelURL = FURL(&DefaultURL, *(GameMapsSettings->GetGameDefaultMap() + GameMapsSettings->LocalMapOptions), TRAVEL_Partial).ToString();
						PotentialWorldContext.TravelType = TRAVEL_Partial;
					}
				}
			}
		}
	}
}

You need to change this function has you need.
Mostly this line
PotentialWorldContext.TravelURL = FURL(&DefaultURL, *(GameMapsSettings->GetGameDefaultMap() + GameMapsSettings->LocalMapOptions), TRAVEL_Partial).ToString();

Require to build yourself the engine by the way.