Struggling to differentiate player controllers in networking setup

I’m having trouble getting some basic networking to work. Here’s the requirement: the project has 2 PC’s, one with a touch screen, and one with nothing but a monitor. The touch screen PC doubles as the listen server, since all user interaction is done there. The monitor PC copies what is happening on the touch screen, save for some different camera perspectives and different UI elements.

The way I originally wanted to do it is have two player controllers, one for each PC. The reasoning behind this is that many different pawns are possessed during runtime, and both require different UI that is independent of which pawn is active. However, it seems that this is not how the Unreal framework is supposed to be used - as far as I can find, only a single kind of player controller can be used simultaneously (please correct me if this is wrong). I can get the same functionality (just less neatly) by simply having a boolean flag in a common player controller though, so this is not the main issue.

The problems arise when trying to differentiate the two PC’s. I tried several methods, all without success:

  • Setting the default player controller class in Login(), right before the player controller is spawned, based on the amount of players. This was in the assumption that different player controllers can be used.
  • Based on a command line argument on the client, RPC to the server from the client after PostLogin() saying that it’s the monitor application.
  • Currently, I’m setting a replicated boolean on the player controller from the game mode in PostLogin(), as follows:

void ACustomGameMode::PostLogin(APlayerController * newPlayer)
{
	Super::PostLogin(newPlayer);

	if (auto playerController= Cast<ACustomPlayerController>(newPlayer))
	{
		// When a player is already present (i.e. the listen server), set the second player controller to being the monitor application.
		if (GetNumPlayers() > 1)
		{
			playerController->IsMonitorController = true;
		}
		playerController->Client_InitPostLogin();
	}
}


void ACustomPlayerController::Client_InitPostLogin_Implementation()
{
	if (IsMonitorController)
	{
		InitializeMonitorPlayerController();
	}
	else
	{
		InitializeTouchScreenPlayerController();
	}
}

However, the related game mode functions are called on the client (the monitor PC), not on the listen server, as soon as the client process launches - the amount of players is still 1 on the client game mode at that point. I read that the game mode only exists on the server, but clearly this is not the case as the client process is directly executing functions on it.

I’m at a loss and very confused - any pointer as to what I’m missing is greatly appreciated.