WorldSettings::Pauser doesn't always replicate when the game is paused

I ran into this issue in current 4.15. I searched and found UE-34407. Unreal Engine Issues and Bug Tracker (UE-34407)

The issue shows Affect Versions 4.12.5 and the issue has been marked as resolved as of Feb 17, 2017.

The issue is marked as Won’t Fix: with comment:
This issue has been closed as ‘Won’t Fix’ due to an extended period of time without updates. If this issue is important to you please let us know by posting on the AnswerHub or UDN, and Epic will re-open the ticket for further review.

Please reopen the issue and add version 4.15.

For clarification, I have overridden the PlayerController pausing functions to support multi player. I’m able to have my PlayerController clients call their PlayerControllers on the server and have the server call SetPause on the GameMode. SetPause and ClearPause succeeded as expected. I traced the problem to WorldSettings::Pauser. It is being set on the server. But the clients are (the vast majorly of the time) not getting updated.

Thanks

Hey HyperToxic,

I originally offered a suggestion to fix this by doing the following:

[MyGameMode.cpp]

// Function Override
bool AAH306237GameMode::SetPause( APlayerController* PC, FCanUnpause CanUnpauseDelegate )
{
	if( Super::SetPause(PC, CanUnpauseDelegate)  )
	{
		for( FConstPawnIterator Iterator = GetWorld()->GetPawnIterator(); Iterator; ++Iterator )
		{
			ATCharacter *Character = Cast<ATCharacter>( *Iterator );
			if( Character )
			{
				Character->RecievePauser( PC->PlayerState );
			}
		}
		return true;
	}
	return false;
}

[MyCharacter.h]

UFUNCTION( client, reliable )
void RecievePauser( APlayerState *Pauser );

[MyCharacer.cpp]

void ATCharacter::RecievePauser_Implementation( APlayerState *Pauser )
{
	if( Pauser )
	{
		PauserName = Pauser->GetName( );
	}
}

This should force the replication of the pause, prior to pause being set.

Kyle,

Thank you so much. However, I’m not sure in my case how setting PauserName in some ATCharacter would help. As WorldSettings()->Pauser() is NULL on most of the clients most of the time. I do see how this would force the server to send Pauser to all ATCharacters on clients, but I fail to understand how it would force the replication of the WorldSettings()->Pauser(). As IsGamePaused() is basically { WorldSettings()->Pauser() != nullptr }.

I did find a hack solution after writing this Awnser Hub though, my solution was was to also to override GameMode::SetPause() and call the Super implementation, I also had to override GameMode::ClearPause() because that was also not replicated most of the time.

In my case I iterate the PlayerContollers in GameMode::SetPause() and GameMode::ClearPause() on the server and call a new client replicated function called APlayerContoller::ClientSetPauser(Pauser) which basically directly sets WorldSettings()->Pauser to Pauser or nullptr (in case of clear) on all clients.

Thank you again for posting your solution. I’m going to post mine here because, google showed hundreds if not thousands of people having the same problem.

I love Unreal, yet its insane to think that this broken pause behavior is still the default behavior everyone gets to see all the time. It smells like a bug, it acts like a bug it must be a bug.

Here is my code, it works for single-player, multi-player and on dedicated server. No blueprints are required. Just call PlayerContoller.Pause() on the client or server or by blueprint.

[RTSGameMode.h]

public:
	virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
	virtual bool ClearPause() override;
private:
	void CallAllClientsSetWorldSettingsPauser(APlayerState* Pauser);

[RTSGameMode.cpp]

bool ARTSGameMode::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate /*= FCanUnpause()*/)
{
	if (Super::SetPause(PC, CanUnpauseDelegate))
	{
		//hack because replication during pause is not working correctly.
		CallAllClientsSetWorldSettingsPauser(PC->PlayerState);
		return true;
	}

	return false;
}

bool ARTSGameMode::ClearPause()
{
	if (Super::ClearPause())
	{
		//hack because replication during pause is not working correctly.
		CallAllClientsSetWorldSettingsPauser(nullptr);
		return true;
	}

	return false;
}

//hack because replication during pause is not working correctly.
void ARTSGameMode::CallAllClientsSetWorldSettingsPauser(APlayerState* Pauser)
{
	for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator)
	{
		ARTSPlayerController* PlayerController = Cast<ARTSPlayerController>(*Iterator);
		PlayerController->ClientSetPauser(Pauser);
	}
}

[RTSPlayerController.h]

public:
	UFUNCTION(BlueprintCallable)
	virtual void Pause() override;

	UFUNCTION(reliable, client)
	void ClientSetPauser(APlayerState* Pauser);

private:
	UFUNCTION(reliable, server, WithValidation)
	void ServerPauseGame();

[RTSPlayerController.cpp]

void ARTSPlayerController::Pause()
{
	ServerPauseGame();
}

bool ARTSPlayerController::ServerPauseGame_Validate()
{
	return true;
}

void ARTSPlayerController::ServerPauseGame_Implementation()
{
	bool result = SetPause(!IsPaused());
}

void ARTSPlayerController::ClientSetPauser_Implementation(APlayerState* Pauser)
{
	AWorldSettings * WorldSettings = GetWorldSettings();
	if (WorldSettings)
		WorldSettings->Pauser = Pauser;
}