RouteGamepadToSecondWindow

RouteGamepadToSecondWindow

#Overview

name: RouteGamepadToSecondWindow

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 6 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of RouteGamepadToSecondWindow is to control the routing of gamepad input to a second window in a multi-client Play-in-Editor (PIE) scenario. This setting is primarily used for testing multiplayer gameplay within the Unreal Editor.

This setting variable is mainly relied upon by the Unreal Engine’s Editor subsystem, specifically the Play-in-Editor functionality. It’s also utilized by the Engine’s input handling system.

The value of this variable is set in the LevelEditorPlaySettings class, which is part of the UnrealEd module. It’s defined as a config property, meaning it can be modified through project settings or configuration files.

RouteGamepadToSecondWindow interacts closely with other variables such as RunUnderOneProcess and PlayNumberOfClients. It’s often used in conjunction with these variables to determine the behavior of gamepad input routing.

Developers must be aware that this variable only takes effect when:

  1. Multiple PIE clients are running (PlayNumberOfClients > 1)
  2. Clients are running under one process (RunUnderOneProcess is true)
  3. The setting itself is enabled (RouteGamepadToSecondWindow is true)

Best practices when using this variable include:

  1. Use it in conjunction with other multiplayer testing settings for a comprehensive test environment.
  2. Be aware that enabling this setting will change the default input behavior, which might affect gameplay testing.
  3. Remember to disable this setting when it’s not needed to ensure consistent input behavior across different test scenarios.
  4. When enabled, ensure that the second window is properly set up and visible to receive the routed input.

This setting is particularly useful for developers working on split-screen or multi-controller multiplayer games, as it allows for testing multiple gamepad inputs in separate windows within the editor environment.

#Setting Variables

#References In INI files

Location: <Workspace>/Projects/Lyra/Config/DefaultEditorPerProjectUserSettings.ini:6, section: [/Script/UnrealEd.LevelEditorPlaySettings]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorPlaySettings.h:384

Scope (from outer to inner):

file
class        class ULevelEditorPlaySettings : public UObject

Source code excerpt:

	 */
	UPROPERTY(config, EditAnywhere, Category="Multiplayer Options|Client", meta=(EditCondition = "RunUnderOneProcess"))
	bool RouteGamepadToSecondWindow;

	/** 
	* If checked, a separate audio device is created for every player. 
	
	* If unchecked, a separate audio device is created for only the first two players and uses the main audio device for more than 2 players.
	*

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorPlaySettings.h:486

Scope (from outer to inner):

file
class        class ULevelEditorPlaySettings : public UObject
function     bool GetRouteGamepadToSecondWindow

Source code excerpt:

	
	bool IsRouteGamepadToSecondWindowActive() const { return PlayNumberOfClients > 1; }
	bool GetRouteGamepadToSecondWindow( bool &OutRouteGamepadToSecondWindow ) const { OutRouteGamepadToSecondWindow = RouteGamepadToSecondWindow; return IsRouteGamepadToSecondWindowActive(); }
	EVisibility GetRouteGamepadToSecondWindowVisibility() const { return (RunUnderOneProcess ? EVisibility::Visible : EVisibility::Hidden); }

	EVisibility GetNetworkEmulationVisibility() const { return (PlayNumberOfClients > 1) ? EVisibility::Visible : EVisibility::Hidden; }

	bool IsServerMapNameOverrideActive() const { return false /*(PlayNetMode == PIE_StandaloneWithServer)*/; }
	bool GetServerMapNameOverride( FString& OutStandaloneServerMapName ) const { OutStandaloneServerMapName = ServerMapNameOverride; return IsServerMapNameOverrideActive(); }

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp:2527

Scope (from outer to inner):

file
function     void UEditorEngine::RemapGamepadControllerIdForPIE

Source code excerpt:

void UEditorEngine::RemapGamepadControllerIdForPIE(class UGameViewportClient* InGameViewport, int32 &ControllerId)
{
	// Increment the controller id if we are the focused window, and RouteGamepadToSecondWindow is true (and we are running multiple clients).
	// This cause the focused window to NOT handle the input, decrement controllerID, and pass it to the next window.
	const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
	const bool CanRouteGamepadToSecondWindow = [&PlayInSettings]{ bool RouteGamepadToSecondWindow(false); return (PlayInSettings->GetRouteGamepadToSecondWindow(RouteGamepadToSecondWindow) && RouteGamepadToSecondWindow); }();
	const bool CanRunUnderOneProcess = [&PlayInSettings]{ bool RunUnderOneProcess(false); return (PlayInSettings->GetRunUnderOneProcess(RunUnderOneProcess) && RunUnderOneProcess); }();
	if ( CanRouteGamepadToSecondWindow && CanRunUnderOneProcess && InGameViewport->GetWindow().IsValid() && InGameViewport->GetWindow()->HasFocusedDescendants())
	{
		ControllerId++;
	}
}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp:502

Scope (from outer to inner):

file
function     ULevelEditorPlaySettings::ULevelEditorPlaySettings

Source code excerpt:

	ServerPort = 17777;
	RunUnderOneProcess = true;
	RouteGamepadToSecondWindow = false;
	BuildGameBeforeLaunch = EPlayOnBuildMode::PlayOnBuild_Default;
	LaunchConfiguration = EPlayOnLaunchConfiguration::LaunchConfig_Default;
	bAutoCompileBlueprintsOnLaunch = true;
	CenterNewWindow = false;
	NewWindowPosition = FIntPoint::NoneValue; // It will center PIE to the middle of the screen the first time it is run (until the user drag the window somewhere else)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp:677

Scope (from outer to inner):

file
function     bool UGameViewportClient::InputKey
lambda-function

Source code excerpt:

		{
			const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
			const bool CanRouteGamepadToSecondWindow = [&PlayInSettings] { bool RouteGamepadToSecondWindow(false); return (PlayInSettings->GetRouteGamepadToSecondWindow(RouteGamepadToSecondWindow) && RouteGamepadToSecondWindow); }();
			const bool CanRunUnderOneProcess = [&PlayInSettings] { bool RunUnderOneProcess(false); return (PlayInSettings->GetRunUnderOneProcess(RunUnderOneProcess) && RunUnderOneProcess); }();
			if (CanRouteGamepadToSecondWindow && CanRunUnderOneProcess && InEventArgs.Viewport->IsPlayInEditorViewport())
			{
				if (UGameViewportClient* NextViewport = GEngine->GetNextPIEViewport(this))
				{
					const bool bResult = NextViewport->InputKey(InEventArgs);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp:773

Scope (from outer to inner):

file
function     bool UGameViewportClient::InputAxis
lambda-function

Source code excerpt:

		{
			const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
			const bool CanRouteGamepadToSecondWindow = [&PlayInSettings] { bool RouteGamepadToSecondWindow(false); return (PlayInSettings->GetRouteGamepadToSecondWindow(RouteGamepadToSecondWindow) && RouteGamepadToSecondWindow); }();
			const bool CanRunUnderOneProcess = [&PlayInSettings] { bool RunUnderOneProcess(false); return (PlayInSettings->GetRunUnderOneProcess(RunUnderOneProcess) && RunUnderOneProcess); }();
			if (CanRouteGamepadToSecondWindow && CanRunUnderOneProcess && InViewport->IsPlayInEditorViewport())
			{
				if (UGameViewportClient* NextViewport = GEngine->GetNextPIEViewport(this))
				{
					const bool bResult = NextViewport->InputAxis(InViewport, InputDevice, Key, Delta, DeltaTime, NumSamples, bGamepad);