2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "IntroTutorialsPrivatePCH.h"
# include "SIntroTutorials.h"
# include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
# include "Editor/MainFrame/Public/MainFrame.h"
# include "Editor/LevelEditor/Public/LevelEditor.h"
# include "Editor/Kismet/Public/BlueprintEditorModule.h"
# include "../Plugins/Editor/EpicSurvey/Source/EpicSurvey/Public/IEpicSurveyModule.h"
# include "Editor/GameProjectGeneration/Public/GameProjectGenerationModule.h"
# include "Editor/UnrealEd/Public/EditorModes.h"
# include "Editor/UnrealEd/Public/SourceCodeNavigation.h"
# include "Editor/Matinee/Public/MatineeModule.h"
# include "EngineAnalytics.h"
# include "Runtime/Analytics/Analytics/Public/Interfaces/IAnalyticsProvider.h"
2014-05-29 17:02:05 -04:00
# include "Particles/ParticleSystem.h"
2014-08-05 09:04:35 -04:00
# include "EditorTutorialSettings.h"
# include "TutorialSettings.h"
# include "Settings.h"
# include "EditorTutorial.h"
# include "SEditorTutorials.h"
# include "STutorialsBrowser.h"
# include "STutorialNavigation.h"
# include "STutorialOverlay.h"
# include "TutorialStructCustomization.h"
# include "EditorTutorialDetailsCustomization.h"
# include "STutorialRoot.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "IntroTutorials"
IMPLEMENT_MODULE ( FIntroTutorials , IntroTutorials )
const FName FIntroTutorials : : IntroTutorialTabName ( TEXT ( " IntroTutorial " ) ) ;
const FString FIntroTutorials : : IntroTutorialConfigSection ( TEXT ( " IntroTutorials " ) ) ;
2014-08-22 01:17:00 -04:00
const FString FIntroTutorials : : DisableTutorialsSettingName ( TEXT ( " DisableAllTutorials " ) ) ;
2014-03-14 14:13:41 -04:00
const FString FIntroTutorials : : InEditorTutorialPath ( TEXT ( " Shared/Tutorials/inEditorTutorial " ) ) ;
const FString FIntroTutorials : : WelcomeTutorialPath ( TEXT ( " Shared/Tutorials/UE4Welcome " ) ) ;
const FString FIntroTutorials : : InEditorGamifiedTutorialPath ( TEXT ( " Shared/Tutorials/inEditorGamifiedTutorial " ) ) ;
const FString FIntroTutorials : : HomePath ( TEXT ( " Shared/Tutorials " ) ) ;
2014-07-24 03:53:33 -04:00
const FString FIntroTutorials : : BlueprintHomePath ( TEXT ( " Shared/Tutorials/TemplateTutorials/TemplateOverview " ) ) ;
const FString FIntroTutorials : : TemplateOverviewPath ( TEXT ( " Shared/Tutorials/UE4Welcome " ) ) ;
2014-03-14 14:13:41 -04:00
const FWelcomeTutorialProperties FIntroTutorials : : UE4WelcomeTutorial ( TEXT ( " Shared/Tutorials/UE4Welcome " ) , TEXT ( " SeenUE4Welcome " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : BlueprintHomeTutorial ( TEXT ( " Shared/Tutorials/InBlueprintEditorTutorial " ) , TEXT ( " SeenBlueprintWelcome " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : ClassBlueprintWelcomeTutorial ( TEXT ( " Shared/Tutorials/BlueprintInterfaceTutorial " ) , TEXT ( " SeenBlueprintWelcome_Class " ) , FString ( " 5DCD4D58-9C9F-407F-8388-75D89CBBA7E8 " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : MacroLibraryBlueprintWelcomeTutorial ( TEXT ( " Shared/Tutorials/BlueprintMacroLibInterfaceTutorial " ) , TEXT ( " SeenBlueprintWelcome_MacroLib " ) , FString ( " 0D5081E0-F29A-4C35-B4DC-1E5E2825AB54 " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : InterfaceBlueprintWelcomeTutorial ( TEXT ( " Shared/Tutorials/BlueprintInterfacesInterfaceTutorial " ) , TEXT ( " SeenBlueprintWelcome_Interface " ) , FString ( " E86E8C9A-4804-4680-B10F-BDC8E95C7AFD " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : LevelScriptBlueprintWelcomeTutorial ( TEXT ( " Shared/Tutorials/LevelBlueprintInterfaceTutorial " ) , TEXT ( " SeenBlueprintWelcome_LevelScript " ) , FString ( " B061E309-517D-4916-BFCB-E8104C8F4C35 " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : AddCodeToProjectWelcomeTutorial ( TEXT ( " Shared/Tutorials/AddCodeToProjectTutorial " ) , TEXT ( " SeenAddCodeToProjectWelcome " ) , FString ( " D8D9A7E7-68B3-4CBE-80FE-4B88C47B7524 " ) ) ;
const FWelcomeTutorialProperties FIntroTutorials : : MatineeEditorWelcomeTutorial ( TEXT ( " Shared/Tutorials/InMatineeEditorTutorial " ) , TEXT ( " SeenMatineeEditorWelcome " ) , FString ( " 6439C991-A77B-4B52-953D-3F29B1DD1860 " ) ) ;
2014-07-24 03:53:33 -04:00
const FWelcomeTutorialProperties FIntroTutorials : : TemplateOverview ( TemplateOverviewPath , TEXT ( " SeenTemplateOverview " ) ) ;
2014-03-14 14:13:41 -04:00
FIntroTutorials : : FIntroTutorials ( )
: CurrentObjectClass ( nullptr )
{
2014-08-22 01:17:00 -04:00
bDisableTutorials = false ;
2014-03-14 14:13:41 -04:00
bEnablePostTutorialSurveys = false ;
2014-06-24 21:29:38 -04:00
bDesireResettingTutorialSeenFlagOnLoad = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " tutorials " ) ) ;
2014-03-14 14:13:41 -04:00
}
/** Generates an analytics name for the given tutorial path string */
FString FIntroTutorials : : AnalyticsEventNameFromTutorialPath ( const FString & TutorialPath ) const
{
// strip off everything but the last folder, supporting both types of slashes
FString RightStr ;
bool bSplit = TutorialPath . Split ( TEXT ( " / " ) , NULL , & RightStr , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) ;
if ( ! bSplit )
{
TutorialPath . Split ( TEXT ( " \\ " ) , NULL , & RightStr , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) ;
}
// then append that to the header
// e.g. Rocket.Tutorials.ClosedInEditorTutorial
FString OutStr ( TEXT ( " Rocket.Tutorials.Closed " ) ) ;
OutStr + = RightStr ;
return OutStr ;
}
TSharedRef < FExtender > FIntroTutorials : : AddSummonBlueprintTutorialsMenuExtender ( const TSharedRef < FUICommandList > CommandList , const TArray < UObject * > EditingObjects ) const
{
UObject * PrimaryObject = nullptr ;
if ( EditingObjects . Num ( ) > 0 )
{
PrimaryObject = EditingObjects [ 0 ] ;
}
TSharedRef < FExtender > Extender ( new FExtender ( ) ) ;
Extender - > AddMenuExtension (
" HelpBrowse " ,
EExtensionHook : : After ,
CommandList ,
FMenuExtensionDelegate : : CreateRaw ( this , & FIntroTutorials : : AddSummonBlueprintTutorialsMenuExtension , PrimaryObject ) ) ;
return Extender ;
}
void FIntroTutorials : : StartupModule ( )
{
2014-08-22 01:17:00 -04:00
GConfig - > GetBool ( * IntroTutorialConfigSection , * DisableTutorialsSettingName , bDisableTutorials , GEditorGameAgnosticIni ) ;
2014-03-14 14:13:41 -04:00
// This code can run with content commandlets. Slate is not initialized with commandlets and the below code will fail.
2014-08-22 01:17:00 -04:00
if ( ! bDisableTutorials & & ! IsRunningCommandlet ( ) )
2014-03-14 14:13:41 -04:00
{
// Add tutorial for main frame opening
IMainFrameModule & MainFrameModule = FModuleManager : : LoadModuleChecked < IMainFrameModule > ( TEXT ( " MainFrame " ) ) ;
MainFrameModule . OnMainFrameCreationFinished ( ) . AddRaw ( this , & FIntroTutorials : : MainFrameLoad ) ;
MainFrameModule . OnMainFrameSDKNotInstalled ( ) . AddRaw ( this , & FIntroTutorials : : HandleSDKNotInstalled ) ;
// Add menu option for level editor tutorial
MainMenuExtender = MakeShareable ( new FExtender ) ;
MainMenuExtender - > AddMenuExtension ( " HelpBrowse " , EExtensionHook : : After , NULL , FMenuExtensionDelegate : : CreateRaw ( this , & FIntroTutorials : : AddSummonTutorialsMenuExtension ) ) ;
FLevelEditorModule & LevelEditorModule = FModuleManager : : LoadModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
LevelEditorModule . GetMenuExtensibilityManager ( ) - > AddExtender ( MainMenuExtender ) ;
// Add menu option to blueprint editor as well
FBlueprintEditorModule & BPEditorModule = FModuleManager : : LoadModuleChecked < FBlueprintEditorModule > ( " Kismet " ) ;
BPEditorModule . GetMenuExtensibilityManager ( ) - > GetExtenderDelegates ( ) . Add ( FAssetEditorExtender : : CreateRaw ( this , & FIntroTutorials : : AddSummonBlueprintTutorialsMenuExtender ) ) ;
// Add hook for when specific asset editor is opened
FAssetEditorManager : : Get ( ) . OnAssetEditorOpened ( ) . AddRaw ( this , & FIntroTutorials : : OnAssetEditorOpened ) ;
IMatineeModule : : Get ( ) . OnMatineeEditorOpened ( ) . AddRaw ( this , & FIntroTutorials : : OnMatineeEditorOpened ) ;
// Add hook for when AddToCodeProject dialog window is opened
FGameProjectGenerationModule : : Get ( ) . OnAddCodeToProjectDialogOpened ( ) . AddRaw ( this , & FIntroTutorials : : OnAddCodeToProjectDialogOpened ) ;
2014-07-24 03:53:33 -04:00
// Add hook for New Project dialog window is opened
//FGameProjectGenerationModule::Get().OnNewProjectProjectDialogOpened().AddRaw(this, &FIntroTutorials::OnNewProjectDialogOpened);
2014-03-14 14:13:41 -04:00
// Add hook for when editor changes modes (e.g. Place/Paint/Landscape/Foliage)
2014-06-18 10:16:16 -04:00
GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . AddRaw ( this , & FIntroTutorials : : OnEditorModeChanged ) ;
2014-03-14 14:13:41 -04:00
FSourceCodeNavigation : : AccessOnCompilerNotFound ( ) . AddRaw ( this , & FIntroTutorials : : HandleCompilerNotFound ) ;
// set up some tutorial data
// NOTE: we match classes based on an "is-a" relationship, so place more derived classes in the map before base classes so they are encountered first
AssetEditorTutorialPropertyMap . Add ( UTexture : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InTextureEditorTutorial " ) , TEXT ( " SeenTextureEditorWelcome " ) , FString ( " 6CC90D96-03D6-4847-B1DF-EB3018C36C4E " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UMaterial : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InMaterialEditorTutorial " ) , TEXT ( " SeenMaterialEditorWelcome " ) , FString ( " 2290389E-A428-46C1-B9BD-A7F110CDF83E " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UAnimBlueprint : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InPersonaAnimBlueprintEditorTutorial " ) , TEXT ( " SeenPersonaAnimBlueprintEditorWelcome " ) , FString ( " FE5CD131-E4AF-4FE6-9269-12B573B66CA8 " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UBlueprint : : StaticClass ( ) , FWelcomeTutorialProperties ( FWelcomeTutorialProperties : : FWelcomeTutorialPropertiesChooserDelegate : : CreateRaw ( this , & FIntroTutorials : : ChooseBlueprintWelcomeTutorial ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UStaticMesh : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InStaticMeshEditorTutorial " ) , TEXT ( " SeenStaticMeshEditorWelcome " ) , FString ( " 762FCAD0-9384-4A6B-8D57-92DA771AD890 " ) ) ) ;
2014-05-07 18:06:40 -04:00
AssetEditorTutorialPropertyMap . Add ( UDestructibleMesh : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InDestructibleMeshEditorTutorial " ) , TEXT ( " SeenDestructibleMeshEditorWelcome " ) , FString ( " 415C385F-C7D3-4CE8-BCC2-F19BB512AF06 " ) ) ) ;
2014-03-14 14:13:41 -04:00
AssetEditorTutorialPropertyMap . Add ( USkeletalMesh : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InSkeletalMeshEditorTutorial " ) , TEXT ( " SeenSkeletalMeshEditorWelcome " ) , FString ( " F8BF69A0-391F-4612-B289-B2B2B3F7F428 " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UParticleSystem : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InParticleSystemEditorTutorial " ) , TEXT ( " SeenParticleSystemEditorWelcome " ) , FString ( " B5ACB9D0-229B-4DA2-A3D6-001A368A48B1 " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( USoundCue : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InSoundCueEditorTutorial " ) , TEXT ( " SeenSoundCueEditorWelcome " ) , FString ( " 3C12B4B3-36F8-48D2-A8B0-874CCD5D3891 " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UMaterialInstance : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InMaterialInstanceEditorTutorial " ) , TEXT ( " SeenMaterialInstanceEditorWelcome " ) , FString ( " A1AAC488-8389-4B71-925D-7A2CFB65F8D4 " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UPhysicsAsset : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InPhATEditorTutorial " ) , TEXT ( " SeenPhATEditorWelcome " ) , FString ( " B576D8AB-9248-4FE4-80F7-96EDA87BBAD3 " ) ) ) ;
// note these 3 go to the same editor
AssetEditorTutorialPropertyMap . Add ( UAnimMontage : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InPersonaAnimEditorTutorial " ) , TEXT ( " SeenPersonaAnimEditorWelcome " ) , FString ( " 8C7C3772-9135-426C-93A7-5937C5CBEA7B " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UAnimSequence : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InPersonaAnimEditorTutorial " ) , TEXT ( " SeenPersonaAnimEditorWelcome " ) , FString ( " 8C7C3772-9135-426C-93A7-5937C5CBEA7B " ) ) ) ;
AssetEditorTutorialPropertyMap . Add ( UBlendSpace : : StaticClass ( ) , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/InPersonaAnimEditorTutorial " ) , TEXT ( " SeenPersonaAnimEditorWelcome " ) , FString ( " 8C7C3772-9135-426C-93A7-5937C5CBEA7B " ) ) ) ;
// map editor modes to tutorial properties
//@todo Placement mode appears to be firing erroneously when switching to other modes, want to understand why before enabling this mode
//EditorModeTutorialPropertyMap.Add(FBuiltinEditorModes::EM_Placement, FWelcomeTutorialProperties(TEXT("Shared/Tutorials/EditorPlacementModeTutorial"), TEXT("SeenEditorPlacementModeWelcome")));
EditorModeTutorialPropertyMap . Add ( FBuiltinEditorModes : : EM_Landscape , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/EditorLandscapeModeTutorial " ) , TEXT ( " SeenEditorLandscapeModeWelcome " ) , FString ( " 8B33592A-CCEE-4129-AE3F-77A5B68955CB " ) ) ) ;
EditorModeTutorialPropertyMap . Add ( FBuiltinEditorModes : : EM_MeshPaint , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/EditorMeshPaintModeTutorial " ) , TEXT ( " SeenEditorMeshPaintModeWelcome " ) , FString ( " 8E36B45D-D249-42E1-ABEE-2ABCBCE8ED26 " ) ) ) ;
EditorModeTutorialPropertyMap . Add ( FBuiltinEditorModes : : EM_Foliage , FWelcomeTutorialProperties ( TEXT ( " Shared/Tutorials/EditorFoliageModeTutorial " ) , TEXT ( " SeenEditorFoliageModeWelcome " ) , FString ( " 9DD00A25-16D5-40D5-BDC4-98DF70CEB0F7 " ) ) ) ;
// init survey map
{
for ( auto It = AssetEditorTutorialPropertyMap . CreateConstIterator ( ) ; It ; + + It )
{
const FWelcomeTutorialProperties & Props = It . Value ( ) ;
TutorialSurveyMap . Add ( Props . TutorialPath , Props . SurveyGuid ) ;
}
for ( auto It = EditorModeTutorialPropertyMap . CreateConstIterator ( ) ; It ; + + It )
{
const FWelcomeTutorialProperties & Props = It . Value ( ) ;
TutorialSurveyMap . Add ( Props . TutorialPath , Props . SurveyGuid ) ;
}
TutorialSurveyMap . Add ( ClassBlueprintWelcomeTutorial . TutorialPath , ClassBlueprintWelcomeTutorial . SurveyGuid ) ;
TutorialSurveyMap . Add ( MacroLibraryBlueprintWelcomeTutorial . TutorialPath , MacroLibraryBlueprintWelcomeTutorial . SurveyGuid ) ;
TutorialSurveyMap . Add ( InterfaceBlueprintWelcomeTutorial . TutorialPath , InterfaceBlueprintWelcomeTutorial . SurveyGuid ) ;
TutorialSurveyMap . Add ( LevelScriptBlueprintWelcomeTutorial . TutorialPath , LevelScriptBlueprintWelcomeTutorial . SurveyGuid ) ;
TutorialSurveyMap . Add ( AddCodeToProjectWelcomeTutorial . TutorialPath , AddCodeToProjectWelcomeTutorial . SurveyGuid ) ;
TutorialSurveyMap . Add ( MatineeEditorWelcomeTutorial . TutorialPath , MatineeEditorWelcomeTutorial . SurveyGuid ) ;
FGuid SurveyGuid ;
// set up some paths for surveys and analytics
SurveyGuid . ParseExact ( FString ( " B6C19629-3172-4924-91FE-AC557F66703C " ) , EGuidFormats : : DigitsWithHyphens , SurveyGuid ) ;
TutorialSurveyMap . Add ( InEditorTutorialPath , SurveyGuid ) ;
SurveyGuid . ParseExact ( FString ( " 3ADE38A2-9FCA-4BA1-B0A3-F64DDFAB2A0E " ) , EGuidFormats : : DigitsWithHyphens , SurveyGuid ) ;
TutorialSurveyMap . Add ( InEditorGamifiedTutorialPath , SurveyGuid ) ;
}
// maybe reset all the "have I seen this once" flags
2014-06-24 21:29:38 -04:00
if ( bDesireResettingTutorialSeenFlagOnLoad )
2014-03-14 14:13:41 -04:00
{
ResetWelcomeTutorials ( ) ;
}
}
2014-08-05 09:04:35 -04:00
// Register to display our settings
ISettingsModule * SettingsModule = ISettingsModule : : Get ( ) ;
if ( SettingsModule ! = nullptr )
{
SettingsModule - > RegisterSettings ( " Editor " , " General " , " Tutorials " ,
LOCTEXT ( " EditorTutorialSettingsName " , " Tutorials " ) ,
LOCTEXT ( " EditorTutorialSettingsDescription " , " Control what tutorials are available in the Editor. " ) ,
GetMutableDefault < UEditorTutorialSettings > ( )
) ;
SettingsModule - > RegisterSettings ( " Project " , " Engine " , " Tutorials " ,
LOCTEXT ( " TutorialSettingsName " , " Tutorials " ) ,
LOCTEXT ( " TutorialSettingsDescription " , " Control what tutorials are available in this project. " ) ,
GetMutableDefault < UTutorialSettings > ( )
) ;
}
// register details customizations
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
PropertyEditorModule . RegisterCustomPropertyTypeLayout ( " TutorialContent " , FOnGetPropertyTypeCustomizationInstance : : CreateStatic ( & FTutorialContentCustomization : : MakeInstance ) ) ;
PropertyEditorModule . RegisterCustomPropertyTypeLayout ( " TutorialContentAnchor " , FOnGetPropertyTypeCustomizationInstance : : CreateStatic ( & FTutorialContentAnchorCustomization : : MakeInstance ) ) ;
PropertyEditorModule . RegisterCustomClassLayout ( " EditorTutorial " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FEditorTutorialDetailsCustomization : : MakeInstance ) ) ;
2014-03-14 14:13:41 -04:00
}
void FIntroTutorials : : ShutdownModule ( )
{
2014-08-22 01:17:00 -04:00
if ( ! bDisableTutorials & & ! IsRunningCommandlet ( ) )
{
FSourceCodeNavigation : : AccessOnCompilerNotFound ( ) . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 01:17:00 -04:00
GLevelEditorModeTools ( ) . OnEditorModeChanged ( ) . RemoveAll ( this ) ;
}
2014-03-14 14:13:41 -04:00
if ( BlueprintEditorExtender . IsValid ( ) & & FModuleManager : : Get ( ) . IsModuleLoaded ( " Kismet " ) )
{
FBlueprintEditorModule & BPEditorModule = FModuleManager : : LoadModuleChecked < FBlueprintEditorModule > ( " Kismet " ) ;
BPEditorModule . GetMenuExtensibilityManager ( ) - > RemoveExtender ( BlueprintEditorExtender ) ;
}
if ( MainMenuExtender . IsValid ( ) & & FModuleManager : : Get ( ) . IsModuleLoaded ( " LevelEditor " ) )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : LoadModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
LevelEditorModule . GetMenuExtensibilityManager ( ) - > RemoveExtender ( MainMenuExtender ) ;
}
if ( FModuleManager : : Get ( ) . IsModuleLoaded ( " MainFrame " ) )
{
IMainFrameModule & MainFrameModule = FModuleManager : : LoadModuleChecked < IMainFrameModule > ( TEXT ( " MainFrame " ) ) ;
MainFrameModule . OnMainFrameCreationFinished ( ) . RemoveAll ( this ) ;
}
2014-08-05 09:04:35 -04:00
ISettingsModule * SettingsModule = ISettingsModule : : Get ( ) ;
if ( SettingsModule ! = nullptr )
{
SettingsModule - > UnregisterSettings ( " Editor " , " General " , " Tutorials " ) ;
SettingsModule - > UnregisterSettings ( " Project " , " Engine " , " Tutorials " ) ;
}
if ( FModuleManager : : Get ( ) . IsModuleLoaded ( " PropertyEditor " ) )
{
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
PropertyEditorModule . UnregisterCustomPropertyTypeLayout ( " TutorialContent " ) ;
PropertyEditorModule . UnregisterCustomPropertyTypeLayout ( " TutorialWidgetReference " ) ;
PropertyEditorModule . UnregisterCustomClassLayout ( " EditorTutorial " ) ;
}
2014-03-14 14:13:41 -04:00
}
void FIntroTutorials : : AddSummonTutorialsMenuExtension ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . BeginSection ( " Tutorials " , LOCTEXT ( " TutorialsLabel " , " Tutorials " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " TutorialsMenuEntryTitle " , " Tutorials " ) ,
LOCTEXT ( " TutorialsMenuEntryToolTip " , " Opens up introductory tutorials covering the basics of using the Unreal Engine 4 Editor. " ) ,
FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tutorials " ) ,
FUIAction ( FExecuteAction : : CreateRaw ( this , & FIntroTutorials : : SummonTutorialHome ) ) ) ;
MenuBuilder . EndSection ( ) ;
}
void FIntroTutorials : : AddSummonBlueprintTutorialsMenuExtension ( FMenuBuilder & MenuBuilder , UObject * PrimaryObject )
{
MenuBuilder . BeginSection ( " Tutorials " , LOCTEXT ( " TutorialsLabel " , " Tutorials " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " BlueprintMenuEntryTitle " , " Blueprint Overview " ) ,
LOCTEXT ( " BlueprintMenuEntryToolTip " , " Opens up an introductory overview of Blueprints. " ) ,
FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tutorials " ) ,
FUIAction ( FExecuteAction : : CreateRaw ( this , & FIntroTutorials : : SummonBlueprintTutorialHome , PrimaryObject , true ) ) ) ;
if ( PrimaryObject ! = nullptr )
{
UBlueprint * BP = Cast < UBlueprint > ( PrimaryObject ) ;
if ( BP ! = nullptr )
{
UEnum * Enum = FindObject < UEnum > ( ANY_PACKAGE , TEXT ( " EBlueprintType " ) , true ) ;
check ( Enum ) ;
MenuBuilder . AddMenuEntry (
FText : : Format ( LOCTEXT ( " BlueprintTutorialsMenuEntryTitle " , " {0} Tutorial " ) , Enum - > GetEnumText ( BP - > BlueprintType ) ) ,
LOCTEXT ( " BlueprintTutorialsMenuEntryToolTip " , " Opens up an introductory tutorial covering this particular part of the Blueprint editor. " ) ,
FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tutorials " ) ,
FUIAction ( FExecuteAction : : CreateRaw ( this , & FIntroTutorials : : SummonBlueprintTutorialHome , PrimaryObject , false ) ) ) ;
}
}
MenuBuilder . EndSection ( ) ;
}
void FIntroTutorials : : MainFrameLoad ( TSharedPtr < SWindow > InRootWindow , bool bIsNewProjectWindow )
{
if ( ! bIsNewProjectWindow )
{
// Save off pointer to root window so we can parent the tutorial window to it when summoned
if ( InRootWindow . IsValid ( ) )
{
RootWindow = InRootWindow ;
}
2014-08-05 09:04:35 -04:00
// install a root widget for the tutorial overlays to hang off
if ( InRootWindow . IsValid ( ) & & ! TutorialRoot . IsValid ( ) )
{
InRootWindow - > AddOverlaySlot ( )
[
SAssignNew ( TutorialRoot , STutorialRoot )
] ;
}
2014-03-14 14:13:41 -04:00
// See if we should show 'welcome' screen
MaybeOpenWelcomeTutorial ( UE4WelcomeTutorial . TutorialPath , UE4WelcomeTutorial . SeenOnceSettingName ) ;
}
}
void FIntroTutorials : : SummonTutorialHome ( )
{
2014-08-05 09:04:35 -04:00
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " NewTutorials " ) ) )
{
FLevelEditorModule & LevelEditorModule = FModuleManager : : LoadModuleChecked < FLevelEditorModule > ( " LevelEditor " ) ;
SummonTutorialBrowser ( LevelEditorModule . GetLevelEditorTab ( ) - > GetParentWindow ( ) . ToSharedRef ( ) ) ;
}
else
{
CurrentObjectClass = nullptr ;
SummonTutorialWindowForPage ( HomePath ) ;
}
2014-03-14 14:13:41 -04:00
}
void FIntroTutorials : : SummonBlueprintTutorialHome ( UObject * Asset , bool bForceWelcome )
{
if ( Asset ! = nullptr )
{
CurrentObjectClass = Asset - > GetClass ( ) ;
}
FWelcomeTutorialProperties const * Tutorial = ChooseBlueprintWelcomeTutorial ( Asset , bForceWelcome ) ;
check ( Tutorial ) ;
SummonTutorialWindowForPage ( Tutorial - > TutorialPath ) ;
2014-06-24 21:29:38 -04:00
// make sure we've seen this tutorial
2014-03-14 14:13:41 -04:00
GConfig - > SetBool ( * IntroTutorialConfigSection , * Tutorial - > SeenOnceSettingName , true , GEditorGameAgnosticIni ) ;
}
void FIntroTutorials : : SummonTutorialWindowForPage ( const FString & Path )
{
TSharedPtr < SWindow > Window ;
// If window already exists, bring it to the front
if ( TutorialWindow . IsValid ( ) )
{
Window = TutorialWindow . Pin ( ) ;
Window - > BringToFront ( ) ;
}
// If not, create a new window
else
{
// Window
Window = SNew ( SWindow )
. Title ( LOCTEXT ( " WindowTitle " , " Tutorials " ) )
. ClientSize ( FVector2D ( 660.f , 637.f ) )
. SupportsMaximize ( false )
. SupportsMinimize ( false ) ;
TutorialWindow = Window ;
2014-08-27 14:11:24 -04:00
if ( RootWindow . IsValid ( ) & & ! PLATFORM_MAC )
2014-03-14 14:13:41 -04:00
{
FSlateApplication : : Get ( ) . AddWindowAsNativeChild ( Window . ToSharedRef ( ) , RootWindow . Pin ( ) . ToSharedRef ( ) ) ;
}
2014-08-27 14:11:24 -04:00
else
{
FSlateApplication : : Get ( ) . AddWindow ( Window . ToSharedRef ( ) ) ;
}
2014-03-14 14:13:41 -04:00
// tutorial Widget
TSharedRef < SIntroTutorials > TutorialWidgetRef =
SNew ( SIntroTutorials )
. ParentWindow ( Window )
. HomeButtonVisibility ( TAttribute < EVisibility > : : Create ( TAttribute < EVisibility > : : FGetter : : CreateRaw ( this , & FIntroTutorials : : GetHomeButtonVisibility ) ) )
. OnGotoNextTutorial ( FOnGotoNextTutorial : : CreateRaw ( this , & FIntroTutorials : : HandleGotoNextTutorial ) ) ;
Window - > SetContent ( TutorialWidgetRef ) ;
Window - > SetOnWindowClosed ( FOnWindowClosed : : CreateRaw ( this , & FIntroTutorials : : OnTutorialWindowClosed ) ) ;
TutorialWidgetRef - > SetOnGoHome ( FOnGoHome : : CreateRaw ( this , & FIntroTutorials : : OnTutorialDismissed ) ) ;
TutorialWidget = TutorialWidgetRef ;
Window - > BringToFront ( ) ;
}
// Change page to desired path
if ( TutorialWidget . IsValid ( ) )
{
TutorialWidget . Pin ( ) - > ChangePage ( Path ) ;
}
}
void FIntroTutorials : : OnTutorialWindowClosed ( const TSharedRef < SWindow > & Window )
{
OnTutorialDismissed ( ) ;
}
void FIntroTutorials : : OnTutorialDismissed ( ) const
{
TSharedPtr < SIntroTutorials > WidgetPtr = TutorialWidget . Pin ( ) ;
if ( WidgetPtr . IsValid ( ) )
{
FString const CurrentPagePath = WidgetPtr - > GetCurrentPagePath ( ) ;
// submit analytics data
if ( FEngineAnalytics : : IsAvailable ( ) )
{
// prepare and send analytics data
bool const bQuitOnWelcomeScreen = ( CurrentPagePath = = WelcomeTutorialPath ) ;
FString const CurrentExcerptTitle = bQuitOnWelcomeScreen ? TEXT ( " Welcome Screen " ) : WidgetPtr - > GetCurrentExcerptIdentifierName ( ) ;
int32 const CurrentExcerptIndex = bQuitOnWelcomeScreen ? - 1 : WidgetPtr - > GetCurrentExcerptIndex ( ) ;
float const CurrentPageElapsedTime = bQuitOnWelcomeScreen ? 0.f : WidgetPtr - > GetCurrentPageElapsedTime ( ) ;
TArray < FAnalyticsEventAttribute > EventAttributes ;
EventAttributes . Add ( FAnalyticsEventAttribute ( TEXT ( " LastExcerptIndex " ) , CurrentExcerptIndex ) ) ;
EventAttributes . Add ( FAnalyticsEventAttribute ( TEXT ( " LastExcerptTitle " ) , CurrentExcerptTitle ) ) ;
EventAttributes . Add ( FAnalyticsEventAttribute ( TEXT ( " TimeSpentInTutorial " ) , CurrentPageElapsedTime ) ) ;
FString AnalyticsEventName = AnalyticsEventNameFromTutorialPath ( CurrentPagePath ) ;
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( AnalyticsEventName , EventAttributes ) ;
}
// kick off survey, but not if it was dismissed immediately
if ( bEnablePostTutorialSurveys & & IEpicSurveyModule : : IsAvailable ( ) & & ( WidgetPtr - > GetCurrentExcerptIndex ( ) > 0 ) )
{
FGuid const * const SurveyID = TutorialSurveyMap . Find ( CurrentPagePath ) ;
if ( SurveyID & & ! SurveyID - > IsValid ( ) )
{
// launch end-of-tutorial survey if one is desired
IEpicSurveyModule : : Get ( ) . PromptSurvey ( * SurveyID ) ;
}
}
}
}
void FIntroTutorials : : OnAssetEditorOpened ( UObject * Asset )
{
if ( Asset ! = nullptr )
{
FWelcomeTutorialProperties const * const FoundProps = FindAssetEditorTutorialProperties ( Asset - > GetClass ( ) ) ;
if ( FoundProps )
{
// run delegate if it exists
FWelcomeTutorialProperties const * const PropsToUse = FoundProps - > ChooserDelegate . IsBound ( )
? FoundProps - > ChooserDelegate . Execute ( Asset )
: FoundProps ;
if ( PropsToUse )
{
2014-04-02 18:09:23 -04:00
if ( MaybeOpenWelcomeTutorial ( PropsToUse - > TutorialPath , PropsToUse - > SeenOnceSettingName ) )
{
CurrentObjectClass = Asset - > GetClass ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
}
FWelcomeTutorialProperties const * FIntroTutorials : : ChooseBlueprintWelcomeTutorial ( UObject * BlueprintObject )
{
return ChooseBlueprintWelcomeTutorial ( BlueprintObject , true ) ;
}
FWelcomeTutorialProperties const * FIntroTutorials : : ChooseBlueprintWelcomeTutorial ( UObject * BlueprintObject , bool bForceWelcome )
{
TutorialChainMap . Empty ( ) ;
UBlueprint * BP = Cast < UBlueprint > ( BlueprintObject ) ;
if ( BP )
{
bool bSeenWelcome = false ;
GConfig - > GetBool ( * IntroTutorialConfigSection , * BlueprintHomeTutorial . SeenOnceSettingName , bSeenWelcome , GEditorGameAgnosticIni ) ;
if ( ! bSeenWelcome | | bForceWelcome )
{
switch ( BP - > BlueprintType )
{
case BPTYPE_Normal :
TutorialChainMap . Add ( BlueprintHomePath , ClassBlueprintWelcomeTutorial . TutorialPath ) ;
break ;
case BPTYPE_MacroLibrary :
TutorialChainMap . Add ( BlueprintHomePath , MacroLibraryBlueprintWelcomeTutorial . TutorialPath ) ;
break ;
case BPTYPE_Interface :
TutorialChainMap . Add ( BlueprintHomePath , InterfaceBlueprintWelcomeTutorial . TutorialPath ) ;
break ;
case BPTYPE_LevelScript :
TutorialChainMap . Add ( BlueprintHomePath , LevelScriptBlueprintWelcomeTutorial . TutorialPath ) ;
break ;
}
}
else
{
switch ( BP - > BlueprintType )
{
case BPTYPE_Normal :
return & ClassBlueprintWelcomeTutorial ;
case BPTYPE_MacroLibrary :
return & MacroLibraryBlueprintWelcomeTutorial ;
case BPTYPE_Interface :
return & InterfaceBlueprintWelcomeTutorial ;
case BPTYPE_LevelScript :
return & LevelScriptBlueprintWelcomeTutorial ;
}
}
}
return & BlueprintHomeTutorial ;
}
FWelcomeTutorialProperties const * FIntroTutorials : : FindAssetEditorTutorialProperties ( UClass const * Class ) const
{
for ( auto It = AssetEditorTutorialPropertyMap . CreateConstIterator ( ) ; It ; + + It )
{
UClass * const KeyClass = It . Key ( ) ;
if ( Class - > IsChildOf ( KeyClass ) )
{
return & It . Value ( ) ;
}
}
return NULL ;
}
2014-04-02 18:09:23 -04:00
bool FIntroTutorials : : MaybeOpenWelcomeTutorial ( const FString & TutorialPath , const FString & ConfigSettingName )
2014-03-14 14:13:41 -04:00
{
2014-08-05 09:04:35 -04:00
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " NewTutorials " ) ) )
{
// try editor startup tutorial
TSubclassOf < UEditorTutorial > EditorStartupTutorialClass = LoadClass < UEditorTutorial > ( NULL , * GetDefault < UEditorTutorialSettings > ( ) - > StartupTutorial . AssetLongPathname , NULL , LOAD_None , NULL ) ;
if ( EditorStartupTutorialClass ! = nullptr )
{
UEditorTutorial * Tutorial = EditorStartupTutorialClass - > GetDefaultObject < UEditorTutorial > ( ) ;
if ( ! GetDefault < UEditorTutorialSettings > ( ) - > HaveSeenTutorial ( Tutorial ) )
{
LaunchTutorial ( Tutorial ) ;
return true ;
}
}
// Try project startup tutorial
TSubclassOf < UEditorTutorial > ProjectStartupTutorialClass = LoadClass < UEditorTutorial > ( NULL , * GetDefault < UTutorialSettings > ( ) - > StartupTutorial . AssetLongPathname , NULL , LOAD_None , NULL ) ;
if ( ProjectStartupTutorialClass ! = nullptr )
{
UEditorTutorial * Tutorial = ProjectStartupTutorialClass - > GetDefaultObject < UEditorTutorial > ( ) ;
if ( ! GetDefault < UEditorTutorialSettings > ( ) - > HaveSeenTutorial ( Tutorial ) )
{
LaunchTutorial ( Tutorial ) ;
return true ;
}
}
return false ;
}
2014-03-14 14:13:41 -04:00
// don't open if viewing any tutorial other than the index
if ( TutorialWidget . IsValid ( ) & & ( TutorialWidget . Pin ( ) - > GetCurrentPagePath ( ) ! = HomePath ) )
{
2014-04-02 18:09:23 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
bool bSeenWelcome = false ;
GConfig - > GetBool ( * IntroTutorialConfigSection , * ConfigSettingName , bSeenWelcome , GEditorGameAgnosticIni ) ;
if ( ! bSeenWelcome )
{
bool const bPageExists = IDocumentation : : Get ( ) - > PageExists ( * TutorialPath ) ;
if ( bPageExists )
{
SummonTutorialWindowForPage ( * TutorialPath ) ;
// Tell ini file that we've seen this now
GConfig - > SetBool ( * IntroTutorialConfigSection , * ConfigSettingName , true , GEditorGameAgnosticIni ) ;
2014-04-02 18:09:23 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-02 18:09:23 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
bool FIntroTutorials : : MaybeOpenWelcomeTutorial ( const FWelcomeTutorialProperties & TutorialProperties )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
return MaybeOpenWelcomeTutorial ( TutorialProperties . TutorialPath , TutorialProperties . SeenOnceSettingName ) ;
2014-03-14 14:13:41 -04:00
}
template < typename KeyType >
void FIntroTutorials : : ResetTutorialPropertyMap ( TMap < KeyType , FWelcomeTutorialProperties > Map ) const
{
for ( auto It = Map . CreateConstIterator ( ) ; It ; + + It )
{
ResetTutorial ( It . Value ( ) ) ;
}
}
void FIntroTutorials : : ResetWelcomeTutorials ( ) const
{
ResetTutorialPropertyMap ( AssetEditorTutorialPropertyMap ) ;
ResetTutorialPropertyMap ( EditorModeTutorialPropertyMap ) ;
ResetTutorial ( UE4WelcomeTutorial ) ;
ResetTutorial ( BlueprintHomeTutorial ) ;
ResetTutorial ( ClassBlueprintWelcomeTutorial ) ;
ResetTutorial ( MacroLibraryBlueprintWelcomeTutorial ) ;
ResetTutorial ( InterfaceBlueprintWelcomeTutorial ) ;
ResetTutorial ( LevelScriptBlueprintWelcomeTutorial ) ;
ResetTutorial ( AddCodeToProjectWelcomeTutorial ) ;
ResetTutorial ( MatineeEditorWelcomeTutorial ) ;
2014-07-24 03:53:33 -04:00
ResetTutorial ( TemplateOverview ) ;
2014-03-14 14:13:41 -04:00
}
void FIntroTutorials : : OnAddCodeToProjectDialogOpened ( )
{
MaybeOpenWelcomeTutorial ( AddCodeToProjectWelcomeTutorial ) ;
}
2014-07-24 03:53:33 -04:00
void FIntroTutorials : : OnNewProjectDialogOpened ( )
{
MaybeOpenWelcomeTutorial ( TemplateOverview ) ;
}
2014-03-14 14:13:41 -04:00
void FIntroTutorials : : OnMatineeEditorOpened ( )
{
MaybeOpenWelcomeTutorial ( MatineeEditorWelcomeTutorial ) ;
}
void FIntroTutorials : : OnEditorModeChanged ( FEdMode * Mode , bool bEnteringMode )
{
// editor-mode changed events can fire before the MainFrameLoad event, so wait until *after* the welcome tutorial to start showing editor-mode tutorials
// this avoids erroneously suppressing a mode tutorial because it opened but was then immediately replaced by the UE4 welcome tutorial
if ( ! HasSeenTutorial ( UE4WelcomeTutorial ) )
return ;
// only show tutorials when entering an editor mode, not when leaving it
if ( bEnteringMode )
{
FWelcomeTutorialProperties const * const FoundProp = EditorModeTutorialPropertyMap . Find ( Mode - > GetID ( ) ) ;
if ( FoundProp )
{
MaybeOpenWelcomeTutorial ( FoundProp - > TutorialPath , FoundProp - > SeenOnceSettingName ) ;
}
}
}
void FIntroTutorials : : HandleCompilerNotFound ( )
{
# if PLATFORM_WINDOWS
SummonTutorialWindowForPage ( TEXT ( " Shared/Tutorials/InstallingVisualStudioTutorial " ) ) ;
# elif PLATFORM_MAC
SummonTutorialWindowForPage ( TEXT ( " Shared/Tutorials/InstallingXCodeTutorial " ) ) ;
2014-08-22 01:17:00 -04:00
# else
STUBBED ( " FIntroTutorials::HandleCompilerNotFound " ) ;
2014-03-14 14:13:41 -04:00
# endif
}
void FIntroTutorials : : HandleSDKNotInstalled ( const FString & PlatformName , const FString & DocLink )
{
SummonTutorialWindowForPage ( DocLink ) ;
}
bool FIntroTutorials : : HasSeenTutorial ( const FWelcomeTutorialProperties & TutProps ) const
{
bool bSeenTutorial = false ;
GConfig - > GetBool ( * IntroTutorialConfigSection , * TutProps . SeenOnceSettingName , bSeenTutorial , GEditorGameAgnosticIni ) ;
return bSeenTutorial ;
}
void FIntroTutorials : : ResetTutorial ( const FWelcomeTutorialProperties & TutProps ) const
{
FString SettingName = TutProps . SeenOnceSettingName ;
if ( ! SettingName . IsEmpty ( ) )
{
GConfig - > SetBool ( * IntroTutorialConfigSection , * SettingName , false , GEditorGameAgnosticIni ) ;
}
}
EVisibility FIntroTutorials : : GetHomeButtonVisibility ( ) const
{
if ( CurrentObjectClass ! = nullptr )
{
return CurrentObjectClass - > IsChildOf ( UBlueprint : : StaticClass ( ) ) ? EVisibility : : Hidden : EVisibility : : Visible ;
}
return EVisibility : : Visible ;
}
FString FIntroTutorials : : HandleGotoNextTutorial ( const FString & InCurrentPage ) const
{
const FString * NextTutorial = TutorialChainMap . Find ( InCurrentPage ) ;
if ( NextTutorial ! = nullptr )
{
return * NextTutorial ;
}
return FString ( ) ;
}
2014-06-24 21:29:38 -04:00
void FIntroTutorials : : RegisterTutorialForAssetEditor ( UClass * AssetClass , const FString & TutorialDocPath , const FString & TutorialHasBeenSeenSettingName , const FString & SurveyGUIDString )
{
FWelcomeTutorialProperties TutorialData ( TutorialDocPath , TutorialHasBeenSeenSettingName , SurveyGUIDString ) ;
if ( bDesireResettingTutorialSeenFlagOnLoad )
{
ResetTutorial ( TutorialData ) ;
}
TutorialSurveyMap . Add ( TutorialDocPath , TutorialData . SurveyGuid ) ;
AssetEditorTutorialPropertyMap . Add ( AssetClass , TutorialData ) ;
}
void FIntroTutorials : : UnregisterTutorialForAssetEditor ( UClass * AssetClass )
{
const FWelcomeTutorialProperties & TutorialData = AssetEditorTutorialPropertyMap . FindChecked ( AssetClass ) ;
TutorialSurveyMap . Remove ( TutorialData . TutorialPath ) ;
AssetEditorTutorialPropertyMap . Remove ( AssetClass ) ;
}
2014-08-05 09:04:35 -04:00
FOnIsPicking & FIntroTutorials : : OnIsPicking ( )
{
return OnIsPickingDelegate ;
}
void FIntroTutorials : : SummonTutorialBrowser ( TSharedRef < SWindow > InWindow , const FString & InFilter )
{
if ( TutorialRoot . IsValid ( ) )
{
TutorialRoot - > SummonTutorialBrowser ( InWindow , InFilter ) ;
}
}
void FIntroTutorials : : LaunchTutorial ( UEditorTutorial * InTutorial , bool bInRestart , TWeakPtr < SWindow > InNavigationWindow )
{
if ( TutorialRoot . IsValid ( ) )
{
TutorialRoot - > LaunchTutorial ( InTutorial , bInRestart , InNavigationWindow ) ;
}
}
2014-08-20 10:27:41 -04:00
void FIntroTutorials : : GoToPreviousStage ( )
{
if ( TutorialRoot . IsValid ( ) )
{
TutorialRoot - > GoToPreviousStage ( ) ;
}
}
void FIntroTutorials : : GoToNextStage ( TWeakPtr < SWindow > InNavigationWindow )
{
if ( TutorialRoot . IsValid ( ) )
{
TutorialRoot - > GoToNextStage ( InNavigationWindow ) ;
}
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE