Delegate for `HandleNetworkFailure`: doesn't fire

I would like to implement a handler for the event FOnNetworkFailure, this is my code:

// Game Instance Subsystem initialization
void UMyGISubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
    Super::Initialize(Collection);

    GEngine->OnNetworkFailure().AddUObject(this, &UMyGISubsystem::HandleNetworkFailure);
}

void UMyGISubsystem::HandleNetworkFailure(UWorld* World, UNetDriver* InNetDriver, ENetworkFailure::Type FailureType,
	const FString& StrError)
{
	UE_LOG(LogNet, Error, TEXT("%s: NetworkFailure: %s"), *GetFullName(), *StrError)
	LeaveSession();
}

I can produce a network failure by calling GameSession->KickPlayer() from within the GameMode, but I never see my log output, nor does my session get destroyed.

This is weird, as there does seem to happen stuff regarding Network Failure in my logs:

[2022.11.01-20.40.00:026][350]LogNet: UChannel::ReceivedSequencedBunch: Bunch.bClose == true. ChIndex == 0. Calling ConditionalCleanUp.
[2022.11.01-20.40.00:026][350]LogNet: UChannel::CleanUp: ChIndex == 0. Closing connection. [UChannel] ChIndex: 0, Closing: 0 [UNetConnection] RemoteAddr: 192.168.1.7:7777, Name: IpConnection_6, Driver: GameNetDriver IpNetDriver_6, IsServer: NO, PC: BP_MyPlayerController_C_0, Owner: BP_MyPlayerController_C_0, UniqueId: NULL:DESKTOP-4092S33-CAF677394FABED484D8F5691C5B9DC80
[2022.11.01-20.40.00:027][350]LogNet: UNetConnection::Close: [UNetConnection] RemoteAddr: 192.168.1.7:7777, Name: IpConnection_6, Driver: GameNetDriver IpNetDriver_6, IsServer: NO, PC: BP_MyPlayerController_C_0, Owner: BP_MyPlayerController_C_0, UniqueId: NULL:DESKTOP-4092S33-CAF677394FABED484D8F5691C5B9DC80, Channels: 3, Time: 2022.11.01-20.40.00
[2022.11.01-20.40.00:028][350]LogNet: UNetConnection::Close: CloseReason:
[2022.11.01-20.40.00:028][350]LogNet:  - Result=ControlChannelClose, ErrorContext="ControlChannelClose"
[2022.11.01-20.40.00:029][350]LogNet: UChannel::Close: Sending CloseBunch. ChIndex == 0. Name: [UChannel] ChIndex: 0, Closing: 0 [UNetConnection] RemoteAddr: 192.168.1.7:7777, Name: IpConnection_6, Driver: GameNetDriver IpNetDriver_6, IsServer: NO, PC: BP_MyPlayerController_C_0, Owner: BP_MyPlayerController_C_0, UniqueId: NULL:DESKTOP-4092S33-CAF677394FABED484D8F5691C5B9DC80
[2022.11.01-20.40.00:029][350]LogNet: Error: UEngine::BroadcastNetworkFailure: FailureType = ConnectionLost, ErrorString = Your connection to the host has been lost., Driver = GameNetDriver IpNetDriver_6
[2022.11.01-20.40.00:030][350]LogNet: Warning: Network Failure: GameNetDriver[ConnectionLost]: Your connection to the host has been lost.
[2022.11.01-20.40.00:030][350]LogNet: NetworkFailure: ConnectionLost, Error: 'Your connection to the host has been lost.'

What, then, is a proper way do deal with some network failure event?

Perhaps it’s network failure as in lost connection or packets not the act of kicking a player?

Interesting. The player does get kicked, though.

perhaps this is what you are looking for?
FHandleDisconnectDelegate

This Delegate exists, but it doesn’t seem to be broadcasted, ever.

I think the delegate needs to be initialized with the add function where you need to pass in the world and unetdriver & user policy, then you can add in addufunction

This definetely works. I registered delegate in my GameInstance::Init().

Also, if you want to properly handle network failures, you can also override Game Engine, but without the part where you add "UnrealEd" in modules. Because you will be unable to create project build. Just override engine for C++ (not editor).

Then, in game engine .h file

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

And CPP file.

void UFragileGameEngine::HandleNetworkFailure(UWorld* World, UNetDriver* NetDriver, ENetworkFailure::Type FailureType,
                                              const FString& ErrorString)
{
	const FName NetDriverName = NetDriver ? NetDriver->NetDriverName : NAME_None;
	if (NetDriverName == NAME_GameNetDriver || NetDriverName == NAME_PendingNetDriver)
	{
		switch (FailureType)
		{
		/** A relevant net driver has already been created for this service */
		case ENetworkFailure::NetDriverAlreadyExists:
			break;
		/** The net driver creation failed */
		case ENetworkFailure::NetDriverCreateFailure:
			break;
		/** The net driver failed its Listen() call */
		case ENetworkFailure::NetDriverListenFailure:
			break;
		/** A connection to the net driver has been lost */
		case ENetworkFailure::ConnectionLost:
			break;
		/** A connection to the net driver has timed out */
		case ENetworkFailure::ConnectionTimeout:
			break;
		/** The net driver received an NMT_Failure message */
		case ENetworkFailure::FailureReceived:
			break;
		/** The client needs to upgrade their game */
		case ENetworkFailure::OutdatedClient:
			break;
		/** The server needs to upgrade their game */
		case ENetworkFailure::OutdatedServer:
			break;
		/** There was an error during connection to the game */
		case ENetworkFailure::PendingConnectionFailure:
			return;
		/** NetGuid mismatch */
		case ENetworkFailure::NetGuidMismatch:
			break;
		/** Network checksum mismatch */
		case ENetworkFailure::NetChecksumMismatch:
			break;
		}
		Super::HandleNetworkFailure(World, NetDriver, FailureType, ErrorString);
	}
}

You can see I do return for
case ENetworkFailure::PendingConnectionFailure:, this is to prevent game restart when player fails to join session.

Works like a charm for me :slight_smile:

1 Like