int32 UUpdateGameProjectCommandlet::Main( const FString& InParams )
{
	// Parse command line.
	TArray<FString> Tokens;
	TArray<FString> Switches;
	UCommandlet::ParseCommandLine(*InParams, Tokens, Switches);

	FString Category;
	FText ChangelistDescription = NSLOCTEXT("UpdateGameProjectCmdlet", "ChangelistDescription", "Updated game project");
	bool bAutoCheckout = false;
	bool bAutoSubmit = false;
	bool bSignSampleProject = false;

	const FString CategorySwitch = TEXT("Category=");
	const FString ChangelistDescriptionSwitch = TEXT("ChangelistDescription=");
	for ( int32 SwitchIdx = 0; SwitchIdx < Switches.Num(); ++SwitchIdx )
	{
		const FString& Switch = Switches[SwitchIdx];
		if ( Switch == TEXT("AutoCheckout") )
		{
			bAutoCheckout = true;
		}
		else if ( Switch == TEXT("AutoSubmit") )
		{
			bAutoSubmit = true;
		}
		else if ( Switch == TEXT("SignSampleProject") )
		{
			bSignSampleProject = true;
		}
		else if ( Switch.StartsWith(CategorySwitch) )
		{
			Category = Switch.Mid( CategorySwitch.Len() );
		}
		else if ( Switch.StartsWith(ChangelistDescriptionSwitch) )
		{
			ChangelistDescription = FText::FromString( Switch.Mid( ChangelistDescriptionSwitch.Len() ) );
		}
	}

	if ( !FPaths::IsProjectFilePathSet() )
	{
		UE_LOG(LogUpdateGameProjectCommandlet, Error, TEXT("You must launch with a project file to be able to update it"));
		return 1;
	}

	const FString ProjectFilePath = FPaths::GetProjectFilePath();

	ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
	if ( bAutoCheckout )
	{
		SourceControlProvider.Init();
	}

	FString EngineIdentifier = GEngineVersion.ToString(EVersionComponent::Minor);

	UE_LOG(LogUpdateGameProjectCommandlet, Display, TEXT("Updating project file %s to %s..."), *ProjectFilePath, *EngineIdentifier);

	FText FailReason;
	if ( !FGameProjectGenerationModule::Get().UpdateGameProject(ProjectFilePath, EngineIdentifier, FailReason) )
	{
		UE_LOG(LogUpdateGameProjectCommandlet, Error, TEXT("Couldn't update game project: %s"), *FailReason.ToString());
		return 1;
	}

	if ( bSignSampleProject )
	{
		UE_LOG(LogUpdateGameProjectCommandlet, Display, TEXT("Attempting to sign project file %s..."), *ProjectFilePath);

		FText LocalFailReason;
		if ( IProjectManager::Get().SignSampleProject(ProjectFilePath, Category, LocalFailReason) )
		{
			UE_LOG(LogUpdateGameProjectCommandlet, Display, TEXT("Signed project file %s saved."), *ProjectFilePath);
		}
		else
		{
			UE_LOG(LogUpdateGameProjectCommandlet, Warning, TEXT("%s"), *LocalFailReason.ToString());
		}
	}

	if ( bAutoSubmit )
	{
		if ( !bAutoCheckout )
		{
			// We didn't init SCC above so do it now
			SourceControlProvider.Init();
		}

		if ( ISourceControlModule::Get().IsEnabled() )
		{
			const FString AbsoluteFilename = FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath());
			FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(AbsoluteFilename, EStateCacheUsage::ForceUpdate);
			if ( SourceControlState.IsValid() && SourceControlState->IsCheckedOut() )
			{
				TSharedRef<FCheckIn, ESPMode::ThreadSafe> CheckInOperation = ISourceControlOperation::Create<FCheckIn>();
				CheckInOperation->SetDescription(ChangelistDescription);
				SourceControlProvider.Execute(CheckInOperation, AbsoluteFilename);
			}
		}
	}

	return 0;
}
/**
 * Builds the Matinee Tool Bar
 */
void FMatinee::ExtendToolbar()
{
    struct Local
    {
        static void FillToolbar(FToolBarBuilder& ToolbarBuilder, TSharedRef<SWidget> InterpolationBox, TSharedRef<SWidget> SpeedBox, TSharedRef<SWidget> SnapSettingBox)
        {
            ToolbarBuilder.BeginSection("CurveMode");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().AddKey);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Interpolation");
            {
                ToolbarBuilder.AddWidget(InterpolationBox);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Play");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().Play);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().PlayLoop);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().Stop);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().PlayReverse);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Camera");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().CreateCameraActor);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Speed");
            {
                ToolbarBuilder.AddWidget(SpeedBox);
            }
            ToolbarBuilder.EndSection();

            //ToolbarBuilder.BeginSection("History");
            //{
            //	ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().Undo);
            //	ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().Redo);
            //}
            //ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("SnapSetting");
            {
                ToolbarBuilder.AddWidget(SnapSettingBox);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Curve");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().ToggleCurveEditor);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Snap");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().ToggleSnap);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().ToggleSnapTimeToFrames);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().FixedTimeStepPlayback);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("View");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().FitSequence);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().FitViewToSelected);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().FitLoop);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().FitLoopSequence);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().ViewEndofTrack);
            }
            ToolbarBuilder.EndSection();

            ToolbarBuilder.BeginSection("Record");
            {
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().LaunchRecordWindow);
                ToolbarBuilder.AddToolBarButton(FMatineeCommands::Get().CreateMovie);
            }
            ToolbarBuilder.EndSection();
        }
    };

    TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);

    InitialInterpModeStrings.Empty();
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "Linear", "Linear").ToString()) ) );
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "CurveAuto", "CurveAuto").ToString()) ) );
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "Constant", "Constant").ToString()) ) );
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "CurveUser", "CurveUser").ToString()) ) );
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "CurveBreak", "CurveBreak").ToString()) ) );
    InitialInterpModeStrings.Add( MakeShareable( new FString(NSLOCTEXT("Matinee", "CurveAutoClamped", "CurveAutoClamped").ToString()) ) );

    InitialInterpModeComboBox =
        SNew( STextComboBox )
        .OptionsSource(&InitialInterpModeStrings)
        .InitiallySelectedItem(InitialInterpModeStrings[0])
        .OnSelectionChanged(this, &FMatinee::OnChangeInitialInterpMode)
        .ToolTipText(NSLOCTEXT("Matinee", "ToolTipInitialInterp", "Initial Interp Mode | Selects the curve interpolation mode for newly created keys"))
        ;

    TSharedRef<SWidget> InterpolationBox =
        SNew(SBox)
        .WidthOverride(150)
        [
            SNew(SVerticalBox)
            +SVerticalBox::Slot()
            .Padding(4)
            [
                SNew(STextBlock)
                .Text(NSLOCTEXT("Matinee.Toolbar", "InterpMode", "Interpolation:"))
                .Visibility( this, &FMatinee::GetLargeIconVisibility )
            ]
            +SVerticalBox::Slot()
            .AutoHeight()
            .Padding(4,0)
            [
                InitialInterpModeComboBox.ToSharedRef()
            ]
        ];

    SpeedSettingStrings.Empty();
    SpeedSettingStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "FullSpeed", "100%").ToString()) ) );
    SpeedSettingStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "50Speed", "50%").ToString()) ) );
    SpeedSettingStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "25Speed", "25%").ToString()) ) );
    SpeedSettingStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "10Speed", "10%").ToString()) ) );
    SpeedSettingStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "1Speed", "1%").ToString()) ) );

    SpeedCombo =
        SNew(STextComboBox)
        .OptionsSource(&SpeedSettingStrings)
        .InitiallySelectedItem(SpeedSettingStrings[0])
        .OnSelectionChanged(this, &FMatinee::OnChangePlaySpeed)
        ;

    TSharedRef<SWidget> SpeedBox =
        SNew(SBox)
        .WidthOverride(103)
        [
            SNew(SVerticalBox)
            +SVerticalBox::Slot()
            .Padding(4)
            [
                SNew(STextBlock)
                .Text(NSLOCTEXT("Matinee.Toolbar", "PlaybackSpeed", "Playback Speed:"))
                .Visibility( this, &FMatinee::GetLargeIconVisibility )
            ]
            +SVerticalBox::Slot()
            .AutoHeight()
            .Padding(4,0)
            [
                SpeedCombo.ToSharedRef()
            ]
        ];

    // Append Second Snap Times
    SnapComboStrings.Empty();
    for(int32 i=0; i<ARRAY_COUNT(InterpEdSnapSizes); i++)
    {
        FString SnapCaption = FString::Printf( TEXT("%1.2f"), InterpEdSnapSizes[i] );
        SnapComboStrings.Add( MakeShareable( new FString(SnapCaption) ) );
    }
    // Append FPS Snap Times
    for(int32 i=0; i<ARRAY_COUNT(InterpEdFPSSnapSizes); i++)
    {
        FString SnapCaption = GetInterpEdFPSSnapSizeLocName( i );
        SnapComboStrings.Add( MakeShareable( new FString(SnapCaption) ) );
    }
    // Add option for snapping to other keys.
    SnapComboStrings.Add( MakeShareable( new FString(NSLOCTEXT("UnrealEd", "InterpEd_Snap_Keys", "Snap to Keys" ).ToString()) ) );

    SnapCombo =
        SNew(STextComboBox)
        .OptionsSource(&SnapComboStrings)
        .InitiallySelectedItem(SnapComboStrings[2])
        .OnSelectionChanged(this, &FMatinee::OnChangeSnapSize)
        .ToolTipText( NSLOCTEXT("Matinee", "SnapComboToolTip", "Snap Size | Selects the timeline granularity for snapping and visualization purposes") )
        ;

    TSharedRef<SWidget> SnapSettingBox =
        SNew(SBox)
        .WidthOverride(155)
        [
            SNew(SVerticalBox)
            +SVerticalBox::Slot()
            .Padding(4)
            [
                SNew(STextBlock)
                .Text(NSLOCTEXT("Matinee.Toolbar", "SnapSetting", "Snap Setting:"))
                .Visibility( this, &FMatinee::GetLargeIconVisibility )
            ]
            +SVerticalBox::Slot()
            .AutoHeight()
            .Padding(4,0)
            [
                SnapCombo.ToSharedRef()
            ]
        ];

    ToolbarExtender->AddToolBarExtension(
        "Asset",
        EExtensionHook::After,
        GetToolkitCommands(),
        FToolBarExtensionDelegate::CreateStatic( &Local::FillToolbar, InterpolationBox, SpeedBox, SnapSettingBox)
    );

    AddToolbarExtender(ToolbarExtender);

    IMatineeModule* MatineeModule = &FModuleManager::LoadModuleChecked<IMatineeModule>( "Matinee" );
    AddToolbarExtender(MatineeModule->GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
TSharedRef<SWidget> SReflectorTreeWidgetItem::GenerateWidgetForColumn(const FName& ColumnName)
{
	if (ColumnName == TEXT("WidgetName"))
	{
		return SNew(SHorizontalBox)

		+ SHorizontalBox::Slot()
		.AutoWidth()
		.VAlign(VAlign_Center)
		[
			SNew(SExpanderArrow, SharedThis(this))
		]

		+ SHorizontalBox::Slot()
		.AutoWidth()
		.Padding(2.0f, 0.0f)
		.VAlign(VAlign_Center)
		[
			SNew(STextBlock)
			.Text(this, &SReflectorTreeWidgetItem::GetWidgetType)
			.ColorAndOpacity(this, &SReflectorTreeWidgetItem::GetTint)
		];
	}
	else if (ColumnName == TEXT("WidgetInfo"))
	{
		return SNew(SBox)
			.HAlign(HAlign_Left)
			.VAlign(VAlign_Center)
			.Padding(FMargin(2.0f, 0.0f))
			[
				SNew(SHyperlink)
				.Text(this, &SReflectorTreeWidgetItem::GetReadableLocationAsText)
				.OnNavigate(this, &SReflectorTreeWidgetItem::HandleHyperlinkNavigate)
			];
	}
	else if (ColumnName == "Visibility")
	{
		return SNew(SBox)
			.HAlign(HAlign_Center)
			.VAlign(VAlign_Center)
			.Padding(FMargin(2.0f, 0.0f))
			[
				SNew(STextBlock)
					.Text(this, &SReflectorTreeWidgetItem::GetVisibilityAsString)
			];
	}
	else if (ColumnName == "ForegroundColor")
	{
		TSharedPtr<SWidget> ThisWidget = WidgetInfo.Get()->Widget.Pin();
		FSlateColor Foreground = (ThisWidget.IsValid())
			? ThisWidget->GetForegroundColor()
			: FSlateColor::UseForeground();

		return SNew(SBorder)
			// Show unset color as an empty space.
			.Visibility(Foreground.IsColorSpecified() ? EVisibility::Visible : EVisibility::Hidden)
			// Show a checkerboard background so we can see alpha values well
			.BorderImage(FCoreStyle::Get().GetBrush("Checkerboard"))
			.VAlign(VAlign_Center)
			.Padding(FMargin(2.0f, 0.0f))
			[
				// Show a color block
				SNew(SColorBlock)
					.Color(Foreground.GetSpecifiedColor())
					.Size(FVector2D(16.0f, 16.0f))
			];
	}
	else if (ColumnName == "Address")
	{
		const TSharedPtr<SWidget> TheWidget = WidgetInfo.Get()->Widget.Pin();
		const FText Address = (TheWidget.IsValid())
			? FText::FromString(FString::Printf(TEXT("0x%08X"), TheWidget.Get()))
			: NSLOCTEXT("SWidgetReflector","nullptr","nullptr");
			
		return SNew(SHyperlink)
			.ToolTipText(NSLOCTEXT("SWidgetReflector", "ClickToCopy", "Click to copy address."))
			.Text(Address)
			.OnNavigate_Lambda([Address](){ FPlatformMisc::ClipboardCopy(*Address.ToString()); }) ;
	}
	else
	{
		return SNullWidget::NullWidget;
	}
}
void SBuildProgressWidget::Construct( const FArguments& InArgs )
{
	BorderImage = FEditorStyle::GetBrush("Menu.Background");
	this->ChildSlot
	.VAlign(VAlign_Center)
	[
		SNew( SVerticalBox )
		+SVerticalBox::Slot()
		.AutoHeight()
		.HAlign(HAlign_Fill)
		.Padding( 10.0f, 4.0f )
		[
			SNew(SBorder)
			[
				SNew( SVerticalBox )
				+SVerticalBox::Slot()
				.AutoHeight()
				.HAlign(HAlign_Fill)
				.Padding( 10.0f, 4.0f )
				[
					SNew( STextBlock )
					.Text( NSLOCTEXT("BuildProgress", "BuildStatusLabel", "Build Status") )
					.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
				]
				+SVerticalBox::Slot()
				.AutoHeight()
				.HAlign(HAlign_Fill)
				.Padding( 10.0f, 4.0f )
				[
					SNew( SHorizontalBox)
					+SHorizontalBox::Slot()
					.AutoWidth()
					.Padding( 0, 7.0f )
					[
						SNew( STextBlock )
						.Text( this, &SBuildProgressWidget::OnGetBuildTimeText )
						.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
					]
					+SHorizontalBox::Slot()
					.AutoWidth()
					.Padding(10.0f, 7.0f, 10.0f, 7.0f)
					[
						SNew( STextBlock )
						.Text( this, &SBuildProgressWidget::OnGetProgressText )
						.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
					]
				]
			]
		]
		+SVerticalBox::Slot()
		.AutoHeight()
		.HAlign(HAlign_Fill)
		.Padding(10.0f, 1.0f)
		[
			SNew(SBorder)
			[
				SNew( SVerticalBox )
				+SVerticalBox::Slot()
				.AutoHeight()
				.HAlign(HAlign_Fill)
				.Padding( 10.0f, 4.0f )
				[
					SNew( STextBlock )
					.Text( NSLOCTEXT("BuildProgress", "BuildProgressLabel", "Build Progress") )
					.ShadowOffset( FVector2D( 1.0f, 1.0f ) )
				]
				+SVerticalBox::Slot()
				.AutoHeight()
				.HAlign(HAlign_Fill)
				.Padding( 10.0f, 7.0f, 10.0f, 7.0f )
				[
					SNew(SProgressBar)
					.Percent( this, &SBuildProgressWidget::OnGetProgressFraction )	
				]
			]

		]
		+SVerticalBox::Slot()
		.AutoHeight()
		.Padding(15.0f, 4.0f)
		.HAlign(HAlign_Center)
		[
			SNew(SHorizontalBox)
			+SHorizontalBox::Slot()
			.AutoWidth()
			[
				SNew(SButton)
				.Text( NSLOCTEXT("BuildProgress", "StopBuildButtonLabel", "Stop Build") )
				.ContentPadding( 5 )
				.OnClicked( this, &SBuildProgressWidget::OnStopBuild )
			]
		]
	];

	// Reset progress indicators
	BuildStartTime = -1;
	bStoppingBuild = false;
	SetBuildStatusText( FText::GetEmpty() );
	SetBuildProgressPercent( 0, 100 );
}
void FLevelCollectionModel::SaveLevels(const FLevelModelList& InLevelList)
{
	if (IsReadOnly())
	{
		return;
	}

		
	FLevelModelList		LevelModelsToSave;
	TArray<ULevel*>		LevelsToSave;
	for (auto It = InLevelList.CreateConstIterator(); It; ++It)
	{
		if ((*It)->GetLevelObject())
		{
			if (!(*It)->IsVisible())
			{
				FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted.  Levels must be made visible before they can be saved.") );
				return;
			}
			else if ((*It)->IsLocked())
			{
				FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted.  Level must be unlocked before it can be saved.") );
				return;
			}
						
			LevelModelsToSave.Add(*It);
			LevelsToSave.Add((*It)->GetLevelObject());
		}
	}

	TArray< UPackage* > PackagesNotNeedingCheckout;
	// Prompt the user to check out the levels from source control before saving
	if (FEditorFileUtils::PromptToCheckoutLevels(false, LevelsToSave, &PackagesNotNeedingCheckout))
	{
		for (auto It = LevelsToSave.CreateIterator(); It; ++It)
		{
			FEditorFileUtils::SaveLevel(*It);
		}
	}
	else if (PackagesNotNeedingCheckout.Num() > 0)
	{
		// The user canceled the checkout dialog but some packages didn't need to be checked out in order to save
		// For each selected level if the package its in didn't need to be saved, save the level!
		for (int32 LevelIdx = 0; LevelIdx < LevelsToSave.Num(); ++LevelIdx)
		{
			ULevel* Level = LevelsToSave[LevelIdx];
			if (PackagesNotNeedingCheckout.Contains(Level->GetOutermost()))
			{
				FEditorFileUtils::SaveLevel(Level);
			}
			else
			{
				//remove it from the list, so that only successfully saved levels are highlighted when saving is complete
				LevelModelsToSave.RemoveAt(LevelIdx);
				LevelsToSave.RemoveAt(LevelIdx);
			}
		}
	}

	// Select tiles that were saved successfully
	SetSelectedLevels(LevelModelsToSave);
}
void FColorStructCustomization::OnColorPickerInteractiveBegin()
{
	bIsInteractive = true;

	GEditor->BeginTransaction( NSLOCTEXT("FColorStructCustomization", "SetColorProperty", "Set Color Property") );
}
void FEdModeGeometry::GetFromSource()
{
	GWarn->BeginSlowTask( NSLOCTEXT("EditorModes", "GeometryMode-BeginRebuildingBSPTask", "Rebuilding BSP"), false);

	TArray<HGeomMidPoints> GeomData;

	// Go through each brush and update its components before updating below
	for( int32 i=0; i<GeomObjects.Num(); i++ )
	{
		FGeomObject* GeomObject = GeomObjects[i];
		if(GeomObject && GeomObject->ActualBrush)
		{
#ifdef BSP_RESELECT
			// Cache any information that'll help us reselect the object after it's reconstructed
			CacheSelectedData( GeomData, *GeomObject );
#endif // BSP_RESELECT
			GeomObject->ActualBrush->UnregisterAllComponents();
			if (GeomObject->ActualBrush->GetWorld())
			{
				GeomObject->ActualBrush->RegisterAllComponents();
			}
			delete GeomObject;
		}		
	}
	GeomObjects.Empty();

	TArray<FGeomBase*> SelectedGeom;

	// Notify the selected actors that they have been moved.
	bool bFound = true;
	for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
	{
		AActor* Actor = static_cast<AActor*>( *It );
		checkSlow( Actor->IsA(AActor::StaticClass()) );

		ABrush* BrushActor = Cast< ABrush >( Actor );
		if ( BrushActor )
		{
			if( BrushActor->Brush != NULL )
			{
				FGeomObject* GeomObject			= new FGeomObject();
				GeomObject->SetParentObjectIndex( GeomObjects.Add( GeomObject ) );
				GeomObject->ActualBrush			= BrushActor;
				GeomObject->GetFromSource();
#ifdef BSP_RESELECT
				// Attempt to find all the previously selected geometry on this object if everything has gone OK so far
				if ( bFound && !FindFromCache( GeomData, *GeomObject, SelectedGeom ) )
				{
#ifdef BSP_RESELECT__ALL_OR_NOTHING
					// If it didn't succeed, don't attempt to reselect anything as the user will only end up moving part of their previous selection
					UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find all previously selected geometry data, resetting selection" ) );
					SelectedGeom.Empty();
					GeomData.Empty();
					bFound = false;
#endif // BSP_RESELECT__ALL_OR_NOTHING
				}
#endif // BSP_RESELECT
			}
		}
	}

#ifdef BSP_RESELECT
	// Reselect anything that came close to the cached midpoints
	SelectCachedData( SelectedGeom );
#endif // BSP_RESELECT

	GWarn->EndSlowTask();
}
void FStaticMeshEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{
#if TODO_STATICMESH
	if ( StaticMesh->bHasBeenSimplified && SimplygonLogo && SimplygonLogo->Resource )
	{
		const float LogoSizeX = 64.0f;
		const float LogoSizeY = 40.65f;
		const float Padding = 6.0f;
		const float LogoX = Viewport->GetSizeXY().X - Padding - LogoSizeX;
		const float LogoY = Viewport->GetSizeXY().Y - Padding - LogoSizeY;

		Canvas->DrawTile(
			LogoX,
			LogoY,
			LogoSizeX,
			LogoSizeY,
			0.0f,
			0.0f,
			1.0f,
			1.0f,
			FLinearColor::White,
			SimplygonLogo->Resource,
			SE_BLEND_Opaque );
	}
#endif // #if TODO_STATICMESH

	auto StaticMeshEditor = StaticMeshEditorPtr.Pin();
	auto StaticMeshEditorViewport = StaticMeshEditorViewportPtr.Pin();
	if (!StaticMeshEditor.IsValid() || !StaticMeshEditorViewport.IsValid())
	{
		return;
	}

	const int32 HalfX = Viewport->GetSizeXY().X/2;
	const int32 HalfY = Viewport->GetSizeXY().Y/2;

	// Draw socket names if desired.
	if( bShowSockets )
	{
		for(int32 i=0; i<StaticMesh->Sockets.Num(); i++)
		{
			UStaticMeshSocket* Socket = StaticMesh->Sockets[i];
			if(Socket!=NULL)
			{
				FMatrix SocketTM;
				Socket->GetSocketMatrix(SocketTM, StaticMeshComponent);
				const FVector SocketPos	= SocketTM.GetOrigin();
				const FPlane proj		= View.Project( SocketPos );
				if(proj.W > 0.f)
				{
					const int32 XPos = HalfX + ( HalfX * proj.X );
					const int32 YPos = HalfY + ( HalfY * (proj.Y * -1) );

					FCanvasTextItem TextItem( FVector2D( XPos, YPos ), FText::FromString( Socket->SocketName.ToString() ), GEngine->GetSmallFont(), FLinearColor(FColor(255,196,196)) );
					Canvas.DrawItem( TextItem );	

					const UStaticMeshSocket* SelectedSocket = StaticMeshEditor->GetSelectedSocket();
					if (bManipulating && SelectedSocket == Socket)
					{
						//Figure out the text height
						FTextSizingParameters Parameters(GEngine->GetSmallFont(), 1.0f, 1.0f);
						UCanvas::CanvasStringSize(Parameters, *Socket->SocketName.ToString());
						int32 YL = FMath::TruncToInt(Parameters.DrawYL);

						DrawAngles(&Canvas, XPos, YPos + YL, 
							Widget->GetCurrentAxis(), 
							GetWidgetMode(),
							Socket->RelativeRotation,
							Socket->RelativeLocation);
					}
				}
			}
		}
	}

	TArray<SStaticMeshEditorViewport::FOverlayTextItem> TextItems;

	int32 CurrentLODLevel = StaticMeshEditor->GetCurrentLODLevel();
	if (CurrentLODLevel == 0)
	{
		CurrentLODLevel = ComputeStaticMeshLOD(StaticMesh->RenderData, StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View);
	}
	else
	{
		CurrentLODLevel -= 1;
	}

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "LOD_F", "LOD:  {0}"), FText::AsNumber(CurrentLODLevel))));

	float CurrentScreenSize = ComputeBoundsScreenSize(StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View);
	FNumberFormattingOptions FormatOptions;
	FormatOptions.MinimumFractionalDigits = 3;
	FormatOptions.MaximumFractionalDigits = 6;
	FormatOptions.MaximumIntegralDigits = 6;
	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "ScreenSize_F", "Current Screen Size:  {0}"), FText::AsNumber(CurrentScreenSize, &FormatOptions))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "Triangles_F", "Triangles:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumTriangles(CurrentLODLevel)))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "Vertices_F", "Vertices:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumVertices(CurrentLODLevel)))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "UVChannels_F", "UV Channels:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumUVChannels(CurrentLODLevel)))));

	if( StaticMesh->RenderData->LODResources.Num() > 0 )
	{
		if (StaticMesh->RenderData->LODResources[0].DistanceFieldData != nullptr )
		{
			const FDistanceFieldVolumeData& VolumeData = *(StaticMesh->RenderData->LODResources[0].DistanceFieldData);

			if (VolumeData.Size.GetMax() > 0)
			{
				float MemoryMb = (VolumeData.Size.X * VolumeData.Size.Y * VolumeData.Size.Z * VolumeData.DistanceFieldVolume.GetTypeSize()) / (1024.0f * 1024.0f);

				FNumberFormattingOptions NumberOptions;
				NumberOptions.MinimumFractionalDigits = 2;
				NumberOptions.MaximumFractionalDigits = 2;

				if (VolumeData.bMeshWasClosed)
				{
					TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
						FText::Format(NSLOCTEXT("UnrealEd", "DistanceFieldRes_F", "Distance Field:  {0}x{1}x{2} = {3}Mb"), FText::AsNumber(VolumeData.Size.X), FText::AsNumber(VolumeData.Size.Y), FText::AsNumber(VolumeData.Size.Z), FText::AsNumber(MemoryMb, &NumberOptions))));
				}
				else
				{
					TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
						NSLOCTEXT("UnrealEd", "DistanceFieldClosed_F", "Distance Field:  Mesh was not closed and material was one-sided")));
				}
			}
		}
	}

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "ApproxSize_F", "Approx Size: {0}x{1}x{2}"),
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.X * 2.0f)), // x2 as artists wanted length not radius
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Y * 2.0f)),
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Z * 2.0f)))));

	// Show the number of collision primitives if we are drawing collision.
	if(bShowCollision && StaticMesh->BodySetup)
	{
		TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
			FText::Format(NSLOCTEXT("UnrealEd", "NumPrimitives_F", "Num Primitives:  {0}"), FText::AsNumber(StaticMesh->BodySetup->AggGeom.GetElementCount()))));
	}

	StaticMeshEditorViewport->PopulateOverlayText(TextItems);

	if(bDrawUVs)
	{
		const int32 YPos = 160;
		DrawUVsForMesh(Viewport, &Canvas, YPos);
	}
}
示例#9
0
/** Generates a widget for a TableView row */
TSharedRef<ITableRow> FPListNodeString::GenerateWidget(const TSharedRef<STableViewBase>& OwnerTable)
{
	return GenerateInvalidRow(OwnerTable, NSLOCTEXT("FPListNodeString", "ArrayUsesColumns", "FPListNodeString uses columns"));
}
TSharedRef<SWidget>	SGraphPinObject::GetDefaultValueWidget()
{
	if( AllowSelfPinWidget() )
	{
		UObject* DefaultObject = GraphPinObj->DefaultObject;

		if(GraphPinObj->GetSchema()->IsSelfPin(*GraphPinObj))
		{
			return SNew(SEditableTextBox)
				.Style( FEditorStyle::Get(), "Graph.EditableTextBox" )
				.Text( this, &SGraphPinObject::GetValue )
				.SelectAllTextWhenFocused(false)
				.Visibility( this, &SGraphPinObject::GetDefaultValueVisibility )
				.IsReadOnly(true)
				.ForegroundColor( FSlateColor::UseForeground() );
		}
	}
	// Don't show literal buttons for component type objects
	if (GraphPinObj->GetSchema()->ShouldShowAssetPickerForPin(GraphPinObj))
	{
		return
			SNew(SHorizontalBox)
			.Visibility( this, &SGraphPin::GetDefaultValueVisibility )
			+SHorizontalBox::Slot()
			.AutoWidth()
			.Padding(2,0)
			.MaxWidth(100.0f)
			[
				SAssignNew(AssetPickerAnchor, SComboButton)
				.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
				.ForegroundColor( this, &SGraphPinObject::OnGetComboForeground)
				.ContentPadding( FMargin(2,2,2,1) )
				.ButtonColorAndOpacity( this, &SGraphPinObject::OnGetWidgetBackground )
				.MenuPlacement(MenuPlacement_BelowAnchor)
				.ButtonContent()
				[
					SNew(STextBlock)
					.ColorAndOpacity( this, &SGraphPinObject::OnGetComboForeground )
					.TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" )
					.Font( FEditorStyle::GetFontStyle( "PropertyWindow.NormalFont" ) )
					.Text( this, &SGraphPinObject::OnGetComboTextValue )
					.ToolTipText( this, &SGraphPinObject::GetObjectToolTip )
				]
				.OnGetMenuContent(this, &SGraphPinObject::GenerateAssetPicker)
			]
			// Use button
			+SHorizontalBox::Slot()
			.AutoWidth()
			.Padding(1,0)
			.VAlign(VAlign_Center)
			[
				SAssignNew(UseButton, SButton)
				.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
				.ButtonColorAndOpacity( this, &SGraphPinObject::OnGetWidgetBackground )
				.OnClicked( GetOnUseButtonDelegate() )
				.ContentPadding(1.f)
				.ToolTipText(NSLOCTEXT("GraphEditor", "ObjectGraphPin_Use_Tooltip", "Use asset browser selection"))
				[
					SNew(SImage)
					.ColorAndOpacity( this, &SGraphPinObject::OnGetWidgetForeground )
					.Image( FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_Use")) )
				]
			]
			// Browse button
			+SHorizontalBox::Slot()
			.AutoWidth()
			.Padding(1,0)
			.VAlign(VAlign_Center)
			[
				SAssignNew(BrowseButton, SButton)
				.ButtonStyle( FEditorStyle::Get(), "NoBorder" )
				.ButtonColorAndOpacity( this, &SGraphPinObject::OnGetWidgetBackground )
				.OnClicked( GetOnBrowseButtonDelegate() )
				.ContentPadding(0)
				.ToolTipText(NSLOCTEXT("GraphEditor", "ObjectGraphPin_Browse_Tooltip", "Browse"))
				[
					SNew(SImage)
					.ColorAndOpacity( this, &SGraphPinObject::OnGetWidgetForeground )
					.Image( FEditorStyle::GetBrush(TEXT("PropertyWindow.Button_Browse")) )
				]
			];
	}

	return SNullWidget::NullWidget;
}
示例#11
0
void AGroupActor::AddSelectedActorsToSelectedGroup()
{
	UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
	if (EditorWorld)
	{
		int32 SelectedGroupIndex = -1;
		for(int32 GroupIdx=0; GroupIdx < EditorWorld->ActiveGroupActors.Num(); ++GroupIdx )
		{
			AGroupActor* GroupActor = Cast<AGroupActor>(EditorWorld->ActiveGroupActors[GroupIdx]);
			if( GroupActor != NULL )
			{
				if(GroupActor->HasSelectedActors(false))
				{
					// Assign the index of the selected group.
					// If this is the second group we find, too many groups are selected, return.
					if( SelectedGroupIndex == -1 )
					{
						SelectedGroupIndex = GroupIdx;
					}
					else
					{
						return;
					}
				}
			}
		}

		AGroupActor* SelectedGroup = Cast<AGroupActor>(EditorWorld->ActiveGroupActors[SelectedGroupIndex]);
		if( SelectedGroupIndex != -1 && SelectedGroup != NULL )
		{
			ULevel* GroupLevel = SelectedGroup->GetLevel();

			// We've established that only one group is selected, so we can just call Add on all these actors.
			// Any actors already in the group will be ignored.
		
			TArray<AActor*> ActorsToAdd;

			bool bActorsInSameLevel = true;
			for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
			{
				AActor* Actor = CastChecked<AActor>( *It );
		
				if( Actor->GetLevel() == GroupLevel )
				{
					ActorsToAdd.Add( Actor );
				}
				else
				{
					bActorsInSameLevel = false;
					break;
				}
			}

			if( bActorsInSameLevel )
			{
				if( ActorsToAdd.Num() > 0 )
				{
					const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "Group_Add", "Add Actors to Group") );
					for( int32 ActorIndex = 0; ActorIndex < ActorsToAdd.Num(); ++ActorIndex )
					{
						if ( ActorsToAdd[ActorIndex] != SelectedGroup )
						{
							SelectedGroup->Add( *ActorsToAdd[ActorIndex] );
						}
					}
				}
			}
			else
			{
				FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Group_CantCreateGroupMultipleLevels", "Can't group the selected actors because they are in different levels.") );
			}
		}
	}
}
	void CreateSpritesFromTextures(TArray<UTexture2D*>& Textures)
	{
		const FString DefaultSuffix = TEXT("_Sprite");

		FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
		FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");

		TArray<UObject*> ObjectsToSync;

		for (auto TextureIt = Textures.CreateConstIterator(); TextureIt; ++TextureIt)
		{
			UTexture2D* Texture = *TextureIt;

			// Create the factory used to generate the sprite
			UPaperSpriteFactory* SpriteFactory = ConstructObject<UPaperSpriteFactory>(UPaperSpriteFactory::StaticClass());
			SpriteFactory->InitialTexture = Texture;

			// Create the sprite
			FString Name;
			FString PackageName;

			if (!bExtractSprites)
			{
				// Get a unique name for the sprite
				AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), DefaultSuffix, /*out*/ PackageName, /*out*/ Name);
				const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);

				if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory))
				{
					ObjectsToSync.Add(NewAsset);
				}
			}
			else
			{
				FScopedSlowTask Feedback(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture"));
				Feedback.MakeDialog(true);

				// First extract the rects from the texture
				TArray<FIntRect> ExtractedRects;
				UPaperSprite::ExtractRectsFromTexture(Texture, /*out*/ ExtractedRects);

				// Sort the rectangles by approximate row
				struct FRectangleSortHelper
				{
					FRectangleSortHelper(TArray<FIntRect>& InOutSprites)
					{
						// Sort by Y, then by X (top left corner), descending order (so we can use it as a stack from the top row down)
						TArray<FIntRect> SpritesLeft = InOutSprites;
						SpritesLeft.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.Y == B.Min.Y) ? (A.Min.X > B.Min.X) : (A.Min.Y > B.Min.Y); });
						InOutSprites.Reset();

						// Start pulling sprites out, the first one in each row will dominate remaining ones and cause them to get labeled
						TArray<FIntRect> DominatedSprites;
						DominatedSprites.Empty(SpritesLeft.Num());
 						while (SpritesLeft.Num())
 						{
							FIntRect DominatingSprite = SpritesLeft.Pop();
							DominatedSprites.Add(DominatingSprite);

							// Find the sprites that are dominated (intersect the infinite horizontal band described by the dominating sprite)
							for (int32 Index = 0; Index < SpritesLeft.Num();)
							{
								const FIntRect& CurElement = SpritesLeft[Index];
								if ((CurElement.Min.Y <= DominatingSprite.Max.Y) && (CurElement.Max.Y >= DominatingSprite.Min.Y))
								{
									DominatedSprites.Add(CurElement);
									SpritesLeft.RemoveAt(Index, /*Count=*/ 1, /*bAllowShrinking=*/ false);
								}
								else
								{
									++Index;
								}
							}

							// Sort the sprites in the band by X and add them to the result
							DominatedSprites.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.X < B.Min.X); });
							InOutSprites.Append(DominatedSprites);
							DominatedSprites.Reset();
 						}
					}
				};
				FRectangleSortHelper RectSorter(ExtractedRects);

				Feedback.TotalAmountOfWork = ExtractedRects.Num();

				for (int ExtractedRectIndex = 0; ExtractedRectIndex < ExtractedRects.Num(); ++ExtractedRectIndex)
				{
					Feedback.EnterProgressFrame(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture"));

					FIntRect& ExtractedRect = ExtractedRects[ExtractedRectIndex];
					SpriteFactory->bUseSourceRegion = true;
					SpriteFactory->InitialSourceUV = FVector2D(ExtractedRect.Min.X, ExtractedRect.Min.Y);
					SpriteFactory->InitialSourceDimension = FVector2D(ExtractedRect.Width(), ExtractedRect.Height());

					// Get a unique name for the sprite
					const FString Suffix = FString::Printf(TEXT("%s_%d"), *DefaultSuffix, ExtractedRectIndex);
					AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), Suffix, /*out*/ PackageName, /*out*/ Name);
					const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);

					if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory))
					{
						ObjectsToSync.Add(NewAsset);
					}

					if (GWarn->ReceivedUserCancel()) 
					{
						break;
					}
				}
			}
		}

		if (ObjectsToSync.Num() > 0)
		{
			ContentBrowserModule.Get().SyncBrowserToAssets(ObjectsToSync);
		}
	}
示例#13
0
/** Generate a widget for the specified column name */
TSharedRef<SWidget> FPListNodeFile::GenerateWidgetForColumn(const FName& ColumnName, int32 Depth, ITableRow* RowPtr) 
{
	return GenerateInvalidRow(NSLOCTEXT("PListNodeArray", "PListNodeFileArrayUsesColumns", "PListNodeFile does not use columns"));
}
UPaperFlipbookActorFactory::UPaperFlipbookActorFactory(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	DisplayName = NSLOCTEXT("Paper2D", "PaperFlipbookFactoryDisplayName", "Add Animated Sprite");
	NewActorClass = APaperFlipbookActor::StaticClass();
}
示例#15
0
void AOnlineBeaconClient::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch)
{
	if(NetDriver->ServerConnection)
	{
		check(Connection == NetDriver->ServerConnection);

		// We are the client
#if !(UE_BUILD_SHIPPING && WITH_EDITOR)
		UE_LOG(LogNet, Log, TEXT("Beacon: Client received: %s"), FNetControlMessageInfo::GetName(MessageType));
#endif
		switch (MessageType)
		{
		case NMT_BeaconWelcome:
			{
				Connection->ClientResponse = TEXT("0");
				FNetControlMessage<NMT_Netspeed>::Send(Connection, Connection->CurrentNetSpeed);

				FString BeaconType = GetBeaconType();
				if (!BeaconType.IsEmpty())
				{
					FNetControlMessage<NMT_BeaconJoin>::Send(Connection, BeaconType);
					NetDriver->ServerConnection->FlushNet();
				}
				else
				{
					// Force close the session
					UE_LOG(LogNet, Log, TEXT("Beacon close from invalid beacon type"));
					OnFailure();
				}
				break;
			}
		case NMT_BeaconAssignGUID:
			{
				FNetworkGUID NetGUID;
				FNetControlMessage<NMT_BeaconAssignGUID>::Receive(Bunch, NetGUID);
				if (NetGUID.IsValid())
				{
					Connection->Driver->GuidCache->RegisterNetGUID_Client( NetGUID, this );

					FString BeaconType = GetBeaconType();
					FNetControlMessage<NMT_BeaconNetGUIDAck>::Send(Connection, BeaconType);
					// Server will send ClientOnConnected() when it gets this control message

					// Fail safe for connection to server but no client connection RPC
					FTimerDelegate TimerDelegate = FTimerDelegate::CreateUObject(this, &AOnlineBeaconClient::OnFailure);
					GetWorldTimerManager().SetTimer(TimerHandle_OnFailure, TimerDelegate, BEACON_RPC_TIMEOUT, false);
				}
				else
				{
					// Force close the session
					UE_LOG(LogNet, Log, TEXT("Beacon close from invalid NetGUID"));
					OnFailure();
				}
				break;
			}
		case NMT_Upgrade:
			{
				// Report mismatch.
				uint32 RemoteNetworkVersion;
				FNetControlMessage<NMT_Upgrade>::Receive(Bunch, RemoteNetworkVersion);
				// Upgrade
				const FString ConnectionError = NSLOCTEXT("Engine", "ClientOutdated", "The match you are trying to join is running an incompatible version of the game.  Please try upgrading your game version.").ToString();
				GEngine->BroadcastNetworkFailure(GetWorld(), NetDriver, ENetworkFailure::OutdatedClient, ConnectionError);
				break;
			}
		case NMT_Failure:
			{
				FString ErrorMsg;
				FNetControlMessage<NMT_Failure>::Receive(Bunch, ErrorMsg);
				if (ErrorMsg.IsEmpty())
				{
					ErrorMsg = NSLOCTEXT("NetworkErrors", "GenericBeaconConnectionFailed", "Beacon Connection Failed.").ToString();
				}

				// Force close the session
				UE_LOG(LogNet, Log, TEXT("Beacon close from NMT_Failure %s"), *ErrorMsg);
				OnFailure();
				break;
			}
		case NMT_BeaconJoin:
		case NMT_BeaconNetGUIDAck:
		default:
			{
				// Force close the session
				UE_LOG(LogNet, Log, TEXT("Beacon close from unexpected control message"));
				OnFailure();
				break;
			}
		}
	}	
}
示例#16
0
/** Generate a widget for the specified column name */
TSharedRef<SWidget> FPListNodeString::GenerateWidgetForColumn(const FName& ColumnName, int32 Depth, ITableRow* RowPtr)
{
	if(ColumnName == "PListKeyColumn")
	{
		return
		SNew(SBorder)
		.BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared())
		[
			SNew(SHorizontalBox)

			// Space item representing item expansion
			+ SHorizontalBox::Slot()
			[
				SNew(SSpacer)
				.Size(FVector2D(20 * Depth, 0))
			]

			// Editable key value
			+ SHorizontalBox::Slot()
			.FillWidth(1.0f)
			[
				SAssignNew(KeyStringTextBox, SEditableTextBox)
				.BackgroundColor(this, &FPListNodeString::GetKeyBackgroundColor)
				.ForegroundColor(this, &FPListNodeString::GetKeyForegroundColor)
				.Text(bArrayMember ? FText::FromString(FString::FromInt(ArrayIndex)) : FText::FromString(KeyString))
				.OnTextChanged(this, &FPListNodeString::OnKeyStringChanged)
				.IsReadOnly(bArrayMember)
			]

			// Spacer between type
			+ SHorizontalBox::Slot()
			[
				SNew(SSpacer)
				.Size(FVector2D(30, 0))
			]
		];
	}

	else if(ColumnName == "PListValueTypeColumn")
	{
		return
		SNew(SBorder)
		.BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared())
		[
			SNew(STextBlock)
			.Text(NSLOCTEXT("PListEditor", "stringValueTypeLabel", "string"))
		];
	}

	else if(ColumnName == "PListValueColumn")
	{
		return
		SNew(SBorder)
		.BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared())
		[
			SNew(SHorizontalBox)

			// Editable "value" value
			+ SHorizontalBox::Slot()
			.FillWidth(1.0f)
			[
				SAssignNew(ValueStringTextBox, SEditableTextBox)
				.BackgroundColor(this, &FPListNodeString::GetValueBackgroundColor)
				.ForegroundColor(this, &FPListNodeString::GetValueForegroundColor)
				.Text(FText::FromString(ValueString))
				.OnTextChanged(this, &FPListNodeString::OnValueStringChanged)
			]
		];
	}

	// Invalid column name
	else
	{
		return SNew(STextBlock) .Text(NSLOCTEXT("PListEditor", "UnknownColumn", "Unknown Column"));
	}
}
void FMathStructCustomization::OnBeginSliderMovement()
{
	bIsUsingSlider = true;

	GEditor->BeginTransaction( NSLOCTEXT("FMathStructCustomization", "SetVectorProperty", "Set Vector Property") );
}
const FString& SBlueprintEditorSelectedDebugObjectWidget::GetNoDebugString() const
{
	return NSLOCTEXT("BlueprintEditor", "DebugObjectNothingSelected", "No debug object selected").ToString();
}
FText UK2Node_CastByteToEnum::GetCompactNodeTitle() const
{
	return NSLOCTEXT("K2Node", "CastSymbol", "\x2022");
}
const FString& SBlueprintEditorSelectedDebugObjectWidget::GetDebugAllWorldsString() const
{
	return NSLOCTEXT("BlueprintEditor", "DebugWorldNothingSelected", "All Worlds").ToString();
}
示例#21
0
		FConstructorStatics()
			: ID_Characters(TEXT("Characters"))
			, NAME_Characters(NSLOCTEXT("SpriteCategory", "Characters", "Characters"))
		{
		}
void SBlueprintEditorSelectedDebugObjectWidget::GenerateDebugWorldNames(bool bRestoreSelection)
{
	TSharedPtr<FString> OldSelection;

	// Store off the old selection
	if (bRestoreSelection && DebugWorldsComboBox.IsValid())
	{
		OldSelection = DebugWorldsComboBox->GetSelectedItem();
	}

	DebugWorldNames.Empty();
	DebugWorlds.Empty();

	DebugWorlds.Add(NULL);
	DebugWorldNames.Add(MakeShareable(new FString(GetDebugAllWorldsString())));

	UWorld* PreviewWorld = NULL;
	TSharedPtr<SSCSEditorViewport> PreviewViewportPtr = BlueprintEditor.Pin()->GetSCSViewport();
	if (PreviewViewportPtr.IsValid())
	{
		PreviewWorld = PreviewViewportPtr->GetPreviewScene().GetWorld();
	}

	for (TObjectIterator<UWorld> It; It; ++It)
	{
		UWorld *TestWorld = *It;
		if (!TestWorld || TestWorld->WorldType != EWorldType::PIE)
		{
			continue;
		}

		DebugWorlds.Add(TestWorld);
		ENetMode NetMode = TestWorld->GetNetMode();

		FString WorldName;

		switch (NetMode)
		{
		case NM_Standalone:
			WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldStandalone", "Standalone").ToString();
			break;

		case NM_ListenServer:
			WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldListenServer", "Listen Server").ToString();
			break;

		case NM_DedicatedServer:
			WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldDedicatedServer", "Dedicated Server").ToString();
			break;

		case NM_Client:
			FWorldContext &PieContext = GEngine->WorldContextFromWorld(TestWorld);
			WorldName = FString::Printf(TEXT("%s %d"), *NSLOCTEXT("BlueprintEditor", "DebugWorldClient", "Client").ToString(), PieContext.PIEInstance - 1);
			break;
		};

		DebugWorldNames.Add(MakeShareable(new FString(WorldName)));
	}

	// Attempt to restore the old selection
	if (bRestoreSelection && DebugWorldsComboBox.IsValid())
	{
		bool bMatchFound = false;
		for (int32 WorldIdx = 0; WorldIdx < DebugWorldNames.Num(); ++WorldIdx)
		{
			if (*DebugWorldNames[WorldIdx] == *OldSelection)
			{
				DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[WorldIdx]);
				bMatchFound = true;
				break;
			}
		}

		// No match found, use the default option
		if (!bMatchFound)
		{
			DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[0]);
		}
	}


	// Finally ensure we have a valid selection
	if (DebugWorldsComboBox.IsValid())
	{
		TSharedPtr<FString> CurrentSelection = DebugWorldsComboBox->GetSelectedItem();
		if (DebugWorldNames.Find(CurrentSelection) == INDEX_NONE)
		{
			if (DebugWorldNames.Num() > 0)
			{
				DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[0]);
			}
			else
			{
				DebugWorldsComboBox->ClearSelection();
			}
		}
	}
}
void FLevelCollectionModel::MoveActorsToSelected_Executed()
{
	// If matinee is open, and if an actor being moved belongs to it, message the user
	if (GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit))
	{
		const FEdModeInterpEdit* InterpEditMode = (const FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
		if (InterpEditMode && InterpEditMode->MatineeActor)
		{
			TArray<AActor*> ControlledActors;
			InterpEditMode->MatineeActor->GetControlledActors(ControlledActors);

			// are any of the selected actors in the matinee
			USelection* SelectedActors = GEditor->GetSelectedActors();
			for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter)
			{
				AActor* Actor = CastChecked<AActor>(*Iter);
				if (Actor != nullptr && (Actor == InterpEditMode->MatineeActor || ControlledActors.Contains(Actor)))
				{
					const bool ExitInterp = EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, NSLOCTEXT("UnrealEd", "MatineeUnableToMove", "You must close Matinee before moving actors.\nDo you wish to do this now and continue?"));
					if (!ExitInterp)
					{
						return;
					}
					GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_InterpEdit);
					break;
				}
			}
		}
	}

	MakeLevelCurrent_Executed();
	const FScopedTransaction Transaction( LOCTEXT("MoveSelectedActorsToSelectedLevel", "Move Selected Actors to Level") );
	Editor->MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel());

	RequestUpdateAllLevels();
}
void FWindowsPlatformSplash::Show()
{
	if( !GSplashScreenThread && FParse::Param(FCommandLine::Get(),TEXT("NOSPLASH")) != true )
	{
		const TCHAR* SplashImage = GIsEditor ? TEXT("EdSplash.bmp") : TEXT("Splash.bmp");

		// make sure a splash was found
		FString SplashPath;
		if (GetSplashPath( SplashImage, SplashPath ) == true)
		{
			// In the editor, we'll display loading info
			if( GIsEditor )
			{
				// Set initial startup progress info
				{
					StartSetSplashText( SplashTextType::StartupProgress,
						*NSLOCTEXT("UnrealEd", "SplashScreen_InitialStartupProgress", "Loading..." ).ToString() );
				}

				// Set version info
				{
#if PLATFORM_64BITS
					//These are invariant strings so they don't need to be localized
					const FText PlatformBits = FText::FromString( TEXT( "64" ) );
#else	//PLATFORM_64BITS
					const FText PlatformBits = FText::FromString( TEXT( "32" ) );
#endif	//PLATFORM_64BITS

					const FText GameName = FText::FromString( FApp::GetGameName() );
					
					const FText Version = FText::FromString( GEngineVersion.ToString( FEngineBuildSettings::IsPerforceBuild() ? EVersionComponent::Branch : EVersionComponent::Patch ) );

					FText VersionInfo = FText::Format( NSLOCTEXT("UnrealEd", "UnrealEdTitleWithVersion_F", "Unreal Editor - {0} ({1}-bit) [Version {2}]" ), GameName, PlatformBits, Version );
					FText AppName =     FText::Format( NSLOCTEXT("UnrealEd", "UnrealEdTitle_F",            "Unreal Editor - {0} ({1}-bit)" ), GameName, PlatformBits );

					StartSetSplashText( SplashTextType::VersionInfo1, *VersionInfo.ToString() );

					// Change the window text (which will be displayed in the taskbar)
					GSplashScreenAppName = AppName;
				}

				// Display copyright information in editor splash screen
				{
					const FString CopyrightInfo = NSLOCTEXT( "UnrealEd", "SplashScreen_CopyrightInfo", "Copyright \x00a9 1998-2014   Epic Games, Inc.   All rights reserved." ).ToString();
					StartSetSplashText( SplashTextType::CopyrightInfo, *CopyrightInfo );
				}
			}

			// Spawn a window to receive the Z-order swap when the splashscreen is destroyed.
			// This will prevent the main window from being sent to the background when the splash window closes.
			GSplashScreenGuard = CreateWindow(
				TEXT("STATIC"), 
				TEXT("SplashScreenGuard"),
				0,
				0,
				0,
				0,
				0,
				HWND_MESSAGE,
				(HMENU) NULL,
				hInstance,
				(LPVOID) NULL); 

			if (GSplashScreenGuard)
			{
				ShowWindow(GSplashScreenGuard, SW_SHOW); 
			}
			
			GSplashScreenFileName = FString( FPlatformProcess::BaseDir() ) / SplashPath;
			GSplashScreenThread = CreateThread(NULL, 128 * 1024, (LPTHREAD_START_ROUTINE)StartSplashScreenThread, (LPVOID)NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
		}
	}
}
示例#25
0
/**
 * Executes all pending shadow-map encoding requests.
 * @param	InWorld				World in which the textures exist
 * @param	bLightingSuccessful	Whether the lighting build was successful or not.
 */
void FShadowMap2D::EncodeTextures(UWorld* InWorld , bool bLightingSuccessful)
{
	if ( bLightingSuccessful )
	{
		GWarn->BeginSlowTask( NSLOCTEXT("ShadowMap2D", "BeginEncodingShadowMapsTask", "Encoding shadow-maps"), false );
		const int32 PackedLightAndShadowMapTextureSize = InWorld->GetWorldSettings()->PackedLightAndShadowMapTextureSize;

		// Reset the pending shadow-map size.
		PendingShadowMapSize = 0;

		Sort(PendingShadowMaps.GetData(), PendingShadowMaps.Num(), FCompareShadowMaps());

		// Allocate texture space for each shadow-map.
		TIndirectArray<FShadowMapPendingTexture> PendingTextures;

		for (FShadowMapAllocationGroup& PendingGroup : PendingShadowMaps)
		{
			if (!ensure(PendingGroup.Allocations.Num() >= 1))
			{
				continue;
			}

			int32 MaxWidth = 0;
			int32 MaxHeight = 0;
			for (auto& Allocation : PendingGroup.Allocations)
			{
				MaxWidth = FMath::Max(MaxWidth, Allocation->MappedRect.Width());
				MaxHeight = FMath::Max(MaxHeight, Allocation->MappedRect.Height());
			}

			FShadowMapPendingTexture* Texture = nullptr;

			// Find an existing texture which the shadow-map can be stored in.
			// Shadowmaps will always be 4-pixel aligned...
			for (FShadowMapPendingTexture& ExistingTexture : PendingTextures)
			{
				if (ExistingTexture.AddElement(PendingGroup))
				{
					Texture = &ExistingTexture;
					break;
				}
			}

			if (!Texture)
			{
				int32 NewTextureSizeX = PackedLightAndShadowMapTextureSize;
				int32 NewTextureSizeY = PackedLightAndShadowMapTextureSize;

				// Assumes identically-sized allocations, fit into the smallest square
				const int32 AllocationCountX = FMath::CeilToInt(FMath::Sqrt(FMath::DivideAndRoundUp(PendingGroup.Allocations.Num() * MaxHeight, MaxWidth)));
				const int32 AllocationCountY = FMath::DivideAndRoundUp(PendingGroup.Allocations.Num(), AllocationCountX);
				const int32 AllocationSizeX = AllocationCountX * MaxWidth;
				const int32 AllocationSizeY = AllocationCountY * MaxHeight;

				if (AllocationSizeX > NewTextureSizeX || AllocationSizeY > NewTextureSizeY)
				{
					NewTextureSizeX = FMath::RoundUpToPowerOfTwo(AllocationSizeX);
					NewTextureSizeY = FMath::RoundUpToPowerOfTwo(AllocationSizeY);
				}

				// If there is no existing appropriate texture, create a new one.
				Texture = new FShadowMapPendingTexture(NewTextureSizeX, NewTextureSizeY);
				PendingTextures.Add(Texture);
				Texture->Outer = PendingGroup.TextureOuter;
				Texture->Bounds = PendingGroup.Bounds;
				Texture->ShadowmapFlags = PendingGroup.ShadowmapFlags;
				verify(Texture->AddElement(PendingGroup));
			}

			// Give the texture ownership of the allocations
			for (auto& Allocation : PendingGroup.Allocations)
			{
				Texture->Allocations.Add(Allocation.Release());
			}
		}
		PendingShadowMaps.Empty();

		// Encode all the pending textures.
		for (int32 TextureIndex = 0; TextureIndex < PendingTextures.Num(); TextureIndex++)
		{
			if (bUpdateStatus && (TextureIndex % 20) == 0)
			{
				GWarn->UpdateProgress(TextureIndex, PendingTextures.Num());
			}

			FShadowMapPendingTexture& PendingTexture = PendingTextures[TextureIndex];
			PendingTexture.StartEncoding(InWorld);
		}
		PendingTextures.Empty();

		GWarn->EndSlowTask();
	}
	else
	{
		PendingShadowMaps.Empty();
	}
}
void RHIDetectAndWarnOfBadDrivers()
{
	int32 CVarValue = CVarWarnOfBadDrivers.GetValueOnGameThread();

	if(!GIsRHIInitialized || !CVarValue || GRHIVendorId == 0)
	{
		return;
	}

	FGPUDriverInfo DriverInfo;

	// later we should make the globals use the struct directly
	DriverInfo.VendorId = GRHIVendorId;
	DriverInfo.DeviceDescription = GRHIAdapterName;
	DriverInfo.ProviderName = TEXT("Unknown");
	DriverInfo.InternalDriverVersion = GRHIAdapterInternalDriverVersion;
	DriverInfo.UserDriverVersion = GRHIAdapterUserDriverVersion;
	DriverInfo.DriverDate = GRHIAdapterDriverDate;


#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	// for testing
	if(CVarValue == 2)
	{
		DriverInfo.SetNVIDIA();
		DriverInfo.DeviceDescription = TEXT("Test NVIDIA (bad)");
		DriverInfo.UserDriverVersion = TEXT("346.43");
		DriverInfo.InternalDriverVersion = TEXT("9.18.134.643");
		DriverInfo.DriverDate = TEXT("01-01-1900");
	}
	else if(CVarValue == 3)
	{
		DriverInfo.SetAMD();
		DriverInfo.DeviceDescription = TEXT("Test AMD (bad)");
		DriverInfo.UserDriverVersion = TEXT("Test Catalyst Version");
		DriverInfo.InternalDriverVersion = TEXT("13.152.1.1000");
		DriverInfo.DriverDate = TEXT("09-10-13");
	}
	else if(CVarValue == 4)
	{
		DriverInfo.SetAMD();
		DriverInfo.DeviceDescription = TEXT("Test AMD (good)");
		DriverInfo.UserDriverVersion = TEXT("Test Catalyst Version");
		DriverInfo.InternalDriverVersion = TEXT("15.30.1025.1001");
		DriverInfo.DriverDate = TEXT("01-01-16");
	}
	else if(CVarValue == 5)
	{
		DriverInfo.SetIntel();
		DriverInfo.DeviceDescription = TEXT("Test Intel (good)");
		DriverInfo.UserDriverVersion = TEXT("Test Intel Version");
		DriverInfo.InternalDriverVersion = TEXT("8.15.10.2302");
		DriverInfo.DriverDate = TEXT("01-01-15");
	}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)

	FGPUHardware DetectedGPUHardware(DriverInfo);

	if (DriverInfo.IsValid())
	{
		FBlackListEntry BlackListEntry = DetectedGPUHardware.FindDriverBlacklistEntry();

		if (BlackListEntry.IsValid())
		{
			bool bLatestBlacklisted = DetectedGPUHardware.IsLatestBlacklisted();

			// Note: we don't localize the vendor's name.
			FString VendorString = DriverInfo.ProviderName;
			if (DriverInfo.IsNVIDIA())
			{
				VendorString = TEXT("NVIDIA");
			}
			else if (DriverInfo.IsAMD())
			{
				VendorString = TEXT("AMD");
			}
			else if (DriverInfo.IsIntel())
			{
				VendorString = TEXT("Intel");
			}

			// format message box UI
			FFormatNamedArguments Args;
			Args.Add(TEXT("AdapterName"), FText::FromString(DriverInfo.DeviceDescription));
			Args.Add(TEXT("Vendor"), FText::FromString(VendorString));
			Args.Add(TEXT("RecommendedVer"), FText::FromString(DetectedGPUHardware.GetSuggestedDriverVersion()));
			Args.Add(TEXT("InstalledVer"), FText::FromString(DriverInfo.UserDriverVersion));

			// this message can be suppressed with r.WarnOfBadDrivers=0
			FText LocalizedMsg;
			if (bLatestBlacklisted)
			{
				LocalizedMsg = FText::Format(NSLOCTEXT("MessageDialog", "LatestVideoCardDriverIssueReport","The latest version of the {Vendor} graphics driver has known issues.\n\nPlease install the last known good driver version.\n\n{AdapterName}\n{RecommendedVer} is the last known good\n{InstalledVer} is installed"),Args);
			}
			else
			{
				LocalizedMsg = FText::Format(NSLOCTEXT("MessageDialog", "VideoCardDriverIssueReport","Your {Vendor} graphics driver has known issues.\n\nPlease update to the latest driver version.\n\n{AdapterName}\n{RecommendedVer} is recommended\n{InstalledVer} is installed"),Args);
			}

			FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
				*LocalizedMsg.ToString(),
				*NSLOCTEXT("MessageDialog", "TitleVideoCardDriverIssue", "WARNING: Known issues with graphics driver").ToString());
		}
	}
}
void UAnimCompress_RemoveLinearKeys::DoReduction(UAnimSequence* AnimSeq, const TArray<FBoneData>& BoneData)
{
#if WITH_EDITORONLY_DATA
	// Only need to do the heavy lifting if it will have some impact
	// One of these will always be true for the base class, but derived classes may choose to turn both off (e.g., in PerTrackCompression)
	const bool bRunningProcessor = bRetarget || bActuallyFilterLinearKeys;

	if (GIsEditor && bRunningProcessor)
	{
		GWarn->BeginSlowTask( NSLOCTEXT("UAnimCompress_RemoveLinearKeys", "BeginReductionTaskMessage", "Compressing animation with a RemoveLinearKeys scheme."), false);
	}

	// If the processor is to be run, then additive animations need to be converted from relative to absolute
	const bool bNeedToConvertBackToAdditive = bRunningProcessor ? ConvertFromRelativeSpace(AnimSeq) : false;

	// Separate the raw data into tracks and remove trivial tracks (all the same value)
	TArray<FTranslationTrack> TranslationData;
	TArray<FRotationTrack> RotationData;
	TArray<FScaleTrack> ScaleData;
	SeparateRawDataIntoTracks(AnimSeq->RawAnimationData, AnimSeq->SequenceLength, TranslationData, RotationData, ScaleData);
	FilterBeforeMainKeyRemoval(AnimSeq, BoneData, TranslationData, RotationData, ScaleData);

	if (bRunningProcessor)
	{
#if TIME_LINEAR_KEY_REMOVAL
		double TimeStart = FPlatformTime::Seconds();
#endif
		// compress this animation without any key-reduction to prime the codec
		CompressUsingUnderlyingCompressor(
			AnimSeq,
			BoneData, 
			TranslationData,
			RotationData,
			ScaleData,
			false);

		// now remove the keys which can be approximated with linear interpolation
		ProcessAnimationTracks(
			AnimSeq,
			BoneData,
			TranslationData,
			RotationData, 
			ScaleData);
#if TIME_LINEAR_KEY_REMOVAL
		double ElapsedTime = FPlatformTime::Seconds() - TimeStart;
		UE_LOG(LogAnimationCompression, Log, TEXT("ProcessAnimationTracks time is (%f) seconds"),ElapsedTime);
#endif

		// if previously additive, convert back to relative-space
		if( bNeedToConvertBackToAdditive )
		{
			ConvertToRelativeSpace(AnimSeq, TranslationData, RotationData, ScaleData);
		}
	}

	// Remove Translation Keys from tracks marked bAnimRotationOnly
	FilterAnimRotationOnlyKeys(TranslationData, AnimSeq);

	// compress the final (possibly key-reduced) tracks into the anim sequence buffers
	CompressUsingUnderlyingCompressor(
		AnimSeq,
		BoneData,
		TranslationData,
		RotationData,
		ScaleData,
		true);

	if (GIsEditor && bRunningProcessor)
	{
		GWarn->EndSlowTask();
	}
	AnimSeq->CompressionScheme = static_cast<UAnimCompress*>( StaticDuplicateObject( this, AnimSeq ) );

#endif // WITH_EDITORONLY_DATA
}
示例#28
0
FText UNiagaraNodeInput::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return Input.Name == NAME_None ? NSLOCTEXT("NiagaraNodeInput", "Input", "Input") : FText::FromName(Input.Name);
}
const FFontData& FLegacySlateFontInfoCache::GetFallbackFont()
{
	const FName FallbackFontName = *(FPaths::EngineContentDir() / TEXT("Slate/Fonts/") / (NSLOCTEXT("Slate", "FallbackFont", "DroidSansFallback").ToString() + TEXT(".ttf")));

	// GetFallbackFont is called directly from the font cache, so may be called from multiple threads at once
	FScopeLock Lock(&FallbackFontCS);

	{
		TSharedPtr<const FFontData>* const ExistingFallbackFont = FallbackFonts.Find(FallbackFontName);
		if(ExistingFallbackFont)
		{
			return **ExistingFallbackFont;
		}
	}

	const FString FallbackFontPath = FallbackFontName.ToString();
	UFontBulkData* FontBulkData = NewObject<UFontBulkData>();
	FontBulkData->Initialize(FallbackFontPath);
	TSharedRef<const FFontData> NewFallbackFont = MakeShareable(new FFontData(FallbackFontPath, FontBulkData, EFontHinting::Default));
	FallbackFonts.Add(FallbackFontName, NewFallbackFont);
	return *NewFallbackFont;
}
FText UGameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return NSLOCTEXT("K2Node", "MultiCompare_TagContainerSingleTags", "Compare Tag Container to Other Tags");
}