2020-09-24 00:43:27 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "InputEditorModule.h"
# include "AssetRegistryModule.h"
# include "AssetTypeActions_Base.h"
# include "EnhancedInputModule.h"
# include "DetailCategoryBuilder.h"
# include "DetailLayoutBuilder.h"
# include "Framework/Notifications/NotificationManager.h"
# include "GameFramework/PlayerController.h"
# include "HAL/PlatformFileManager.h"
# include "InputAction.h"
# include "InputMappingContext.h"
2022-01-27 14:09:11 -05:00
# include "PlayerMappableInputConfig.h"
2020-09-24 00:43:27 -04:00
# include "InputCustomizations.h"
# include "InputModifiers.h"
# include "IAssetTools.h"
# include "IAssetTypeActions.h"
# include "IDetailsView.h"
# include "ISettingsModule.h"
# include "K2Node_EnhancedInputAction.h"
# include "K2Node_GetInputActionValue.h"
# include "Modules/ModuleInterface.h"
# include "Modules/ModuleManager.h"
# include "PropertyEditorDelegates.h"
# include "PropertyEditorModule.h"
# include "SSettingsEditorCheckoutNotice.h"
# include "TickableEditorObject.h"
# include "Widgets/Layout/SScrollBox.h"
# include "Widgets/Notifications/SNotificationList.h"
2021-08-12 13:50:48 -04:00
# include "AssetTypeActions/AssetTypeActions_DataAsset.h"
2020-09-24 00:43:27 -04:00
# define LOCTEXT_NAMESPACE "InputEditor"
class FInputEditorModule : public IModuleInterface , public FTickableEditorObject
{
public :
// IModuleInterface interface
virtual void StartupModule ( ) override ;
virtual void ShutdownModule ( ) override ;
// End IModuleInterface interface
// FTickableEditorObject interface
virtual void Tick ( float DeltaTime ) override ;
virtual TStatId GetStatId ( ) const override { RETURN_QUICK_DECLARE_CYCLE_STAT ( FInputEditorModule , STATGROUP_Tickables ) ; }
// End FTickableEditorObject interface
static EAssetTypeCategories : : Type GetInputAssetsCategory ( ) { return InputAssetsCategory ; }
private :
void RegisterAssetTypeActions ( IAssetTools & AssetTools , TSharedRef < IAssetTypeActions > Action )
{
AssetTools . RegisterAssetTypeActions ( Action ) ;
CreatedAssetTypeActions . Add ( Action ) ;
}
2021-05-26 20:29:20 -04:00
void PostEngineInit ( ) ;
2020-09-24 00:43:27 -04:00
TSharedRef < SWidget > CreateSettingsPanel ( ) ;
void OnSettingChanged ( const FPropertyChangedEvent & PropertyChangedEvent ) ;
void RebuildDetailsViewForAsset ( const FAssetData & AssetData , bool bIgnoreAsset ) ;
void OnAssetAdded ( const FAssetData & AssetData ) { RebuildDetailsViewForAsset ( AssetData , false ) ; }
void OnAssetRemoved ( const FAssetData & AssetData ) { RebuildDetailsViewForAsset ( AssetData , true ) ; }
void OnAssetRenamed ( const FAssetData & AssetData , const FString & ) { RebuildDetailsViewForAsset ( AssetData , true ) ; }
template < typename T >
TSharedPtr < IDetailsView > AddClassDetailsView ( ) ;
struct FClassDetailsView
{
FClassDetailsView ( ) = default ;
FClassDetailsView ( UClass * InClass , TSharedPtr < IDetailsView > & InView ) : Class ( InClass ) , View ( InView ) { }
bool IsValid ( ) const { return Class ! = nullptr ; }
UClass * Class = nullptr ;
TSharedPtr < IDetailsView > View ;
} ;
FClassDetailsView FindClassDetailsViewForAsset ( const FAssetData & AssetData ) ;
TArray < UObject * > GatherClassDetailsCDOs ( UClass * Class , const FAssetData * IgnoreAsset ) ;
static EAssetTypeCategories : : Type InputAssetsCategory ;
TArray < TSharedPtr < IAssetTypeActions > > CreatedAssetTypeActions ;
TMap < UClass * , TSharedPtr < IDetailsView > > DetailsViews ;
TSharedPtr < SWidget > Panel ;
} ;
EAssetTypeCategories : : Type FInputEditorModule : : InputAssetsCategory ;
IMPLEMENT_MODULE ( FInputEditorModule , InputEditor )
// Asset factories
// InputContext
UInputMappingContext_Factory : : UInputMappingContext_Factory ( const class FObjectInitializer & OBJ ) : Super ( OBJ ) {
SupportedClass = UInputMappingContext : : StaticClass ( ) ;
bEditAfterNew = true ;
bCreateNew = true ;
}
UObject * UInputMappingContext_Factory : : FactoryCreateNew ( UClass * Class , UObject * InParent , FName Name , EObjectFlags Flags , UObject * Context , FFeedbackContext * Warn )
{
check ( Class - > IsChildOf ( UInputMappingContext : : StaticClass ( ) ) ) ;
return NewObject < UInputMappingContext > ( InParent , Class , Name , Flags | RF_Transactional , Context ) ;
}
// InputAction
2022-01-27 14:09:11 -05:00
UInputAction_Factory : : UInputAction_Factory ( const class FObjectInitializer & OBJ )
: Super ( OBJ )
{
2020-09-24 00:43:27 -04:00
SupportedClass = UInputAction : : StaticClass ( ) ;
bEditAfterNew = true ;
bCreateNew = true ;
}
UObject * UInputAction_Factory : : FactoryCreateNew ( UClass * Class , UObject * InParent , FName Name , EObjectFlags Flags , UObject * Context , FFeedbackContext * Warn )
{
check ( Class - > IsChildOf ( UInputAction : : StaticClass ( ) ) ) ;
return NewObject < UInputAction > ( InParent , Class , Name , Flags | RF_Transactional , Context ) ;
}
2022-01-27 14:09:11 -05:00
// UPlayerMappableInputConfig_Factory
UPlayerMappableInputConfig_Factory : : UPlayerMappableInputConfig_Factory ( const class FObjectInitializer & OBJ )
: Super ( OBJ )
{
SupportedClass = UPlayerMappableInputConfig : : StaticClass ( ) ;
bEditAfterNew = true ;
bCreateNew = true ;
}
UObject * UPlayerMappableInputConfig_Factory : : FactoryCreateNew ( UClass * Class , UObject * InParent , FName Name , EObjectFlags Flags , UObject * Context , FFeedbackContext * Warn )
{
check ( Class - > IsChildOf ( UPlayerMappableInputConfig : : StaticClass ( ) ) ) ;
return NewObject < UPlayerMappableInputConfig > ( InParent , Class , Name , Flags | RF_Transactional , Context ) ;
}
2020-09-24 00:43:27 -04:00
//
//// InputTrigger
//UInputTrigger_Factory::UInputTrigger_Factory(const class FObjectInitializer& OBJ) : Super(OBJ) {
// ParentClass = UInputTrigger::StaticClass();
// SupportedClass = UInputTrigger::StaticClass();
// bEditAfterNew = true;
// bCreateNew = true;
//}
//
//// InputModifier
//UInputModifier_Factory::UInputModifier_Factory(const class FObjectInitializer& OBJ) : Super(OBJ) {
// ParentClass = UInputModifier::StaticClass();
// SupportedClass = UInputModifier::StaticClass();
// bEditAfterNew = true;
// bCreateNew = true;
//}
// Asset type actions
// TODO: Move asset type action definitions out?
2022-01-27 14:09:11 -05:00
class FAssetTypeActions_InputContext : public FAssetTypeActions_DataAsset
{
2020-09-24 00:43:27 -04:00
public :
virtual FText GetName ( ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_InputMappingContext " , " Input Mapping Context " ) ; }
virtual uint32 GetCategories ( ) override { return FInputEditorModule : : GetInputAssetsCategory ( ) ; }
virtual FColor GetTypeColor ( ) const override { return FColor ( 255 , 255 , 127 ) ; }
virtual FText GetAssetDescription ( const FAssetData & AssetData ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_InputContextDesc " , " A collection of device input to action mappings. " ) ; }
virtual UClass * GetSupportedClass ( ) const override { return UInputMappingContext : : StaticClass ( ) ; }
} ;
2022-01-27 14:09:11 -05:00
class FAssetTypeActions_InputAction : public FAssetTypeActions_DataAsset
{
2020-09-24 00:43:27 -04:00
public :
virtual FText GetName ( ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_InputAction " , " Input Action " ) ; }
virtual uint32 GetCategories ( ) override { return FInputEditorModule : : GetInputAssetsCategory ( ) ; }
virtual FColor GetTypeColor ( ) const override { return FColor ( 127 , 255 , 255 ) ; }
virtual FText GetAssetDescription ( const FAssetData & AssetData ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_InputActionDesc " , " Represents an an abstract game action that can be mapped to arbitrary hardware input devices. " ) ; }
virtual UClass * GetSupportedClass ( ) const override { return UInputAction : : StaticClass ( ) ; }
} ;
2022-01-27 14:09:11 -05:00
class FAssetTypeActions_PlayerMappableInputConfig : public FAssetTypeActions_DataAsset
{
public :
virtual FText GetName ( ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_PlayerBindableInputConfig " , " Player Bindable Input Config " ) ; }
virtual uint32 GetCategories ( ) override { return FInputEditorModule : : GetInputAssetsCategory ( ) ; }
virtual FColor GetTypeColor ( ) const override { return FColor ( 127 , 255 , 255 ) ; }
virtual FText GetAssetDescription ( const FAssetData & AssetData ) const override { return NSLOCTEXT ( " AssetTypeActions " , " AssetTypeActions_PlayerBindableInputConfigDesc " , " Represents one set of Player Mappable controller/keymappings " ) ; }
virtual UClass * GetSupportedClass ( ) const override { return UPlayerMappableInputConfig : : StaticClass ( ) ; }
} ;
2021-08-12 13:50:48 -04:00
2020-09-24 00:43:27 -04:00
void FInputEditorModule : : OnSettingChanged ( const FPropertyChangedEvent & PropertyChangedEvent )
{
// TODO: Copy of SSettingsEditor::NotifyPostChange
if ( PropertyChangedEvent . ChangeType ! = EPropertyChangeType : : Interactive )
{
check ( PropertyChangedEvent . GetNumObjectsBeingEdited ( ) < = 1 ) ;
if ( PropertyChangedEvent . GetNumObjectsBeingEdited ( ) > 0 )
{
UObject * ObjectBeingEdited = ( UObject * ) PropertyChangedEvent . GetObjectBeingEdited ( 0 ) ;
// Attempt to checkout the file automatically
if ( ! ObjectBeingEdited - > GetClass ( ) - > HasAnyClassFlags ( CLASS_DefaultConfig ) )
{
return ;
}
FString RelativePath = ObjectBeingEdited - > GetDefaultConfigFilename ( ) ;
FString FullPath = FPaths : : ConvertRelativePathToFull ( RelativePath ) ;
bool bIsNewFile = ! FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * FullPath ) ;
if ( ! SettingsHelpers : : CheckOutOrAddFile ( FullPath ) )
{
SettingsHelpers : : MakeWritable ( FullPath ) ;
}
// Determine if the Property is an Array or Array Element
bool bIsArrayOrArrayElement = PropertyChangedEvent . Property - > IsA ( FArrayProperty : : StaticClass ( ) )
| | PropertyChangedEvent . Property - > ArrayDim > 1
| | PropertyChangedEvent . Property - > GetOwner < FArrayProperty > ( ) ;
bool bIsSetOrSetElement = PropertyChangedEvent . Property - > IsA ( FSetProperty : : StaticClass ( ) )
| | PropertyChangedEvent . Property - > GetOwner < FSetProperty > ( ) ;
bool bIsMapOrMapElement = PropertyChangedEvent . Property - > IsA ( FMapProperty : : StaticClass ( ) )
| | PropertyChangedEvent . Property - > GetOwner < FMapProperty > ( ) ;
if ( ObjectBeingEdited - > GetClass ( ) - > HasAnyClassFlags ( CLASS_DefaultConfig ) & & ! bIsArrayOrArrayElement & & ! bIsSetOrSetElement & & ! bIsMapOrMapElement )
{
if ( PropertyChangedEvent . Property - > HasAnyPropertyFlags ( CPF_Config | CPF_GlobalConfig ) )
{
ObjectBeingEdited - > UpdateSinglePropertyInConfigFile ( PropertyChangedEvent . Property , ObjectBeingEdited - > GetDefaultConfigFilename ( ) ) ;
}
}
if ( bIsNewFile )
{
SettingsHelpers : : CheckOutOrAddFile ( FullPath ) ;
}
}
}
}
template < typename T >
class FPerCDOSettingsCustomization : public IDetailCustomization
{
virtual void CustomizeDetails ( IDetailLayoutBuilder & DetailBuilder ) override
{
TArray < TWeakObjectPtr < UObject > > CustomizedObjects ;
DetailBuilder . GetObjectsBeingCustomized ( CustomizedObjects ) ;
TWeakObjectPtr < UObject > & Object = CustomizedObjects [ 0 ] ;
if ( Object . IsValid ( ) & & Object - > HasAnyFlags ( RF_ClassDefaultObject ) )
{
FString CategoryName = Object - > GetClass ( ) - > GetName ( ) ;
CategoryName . RemoveFromStart ( T : : StaticClass ( ) - > GetName ( ) ) ;
CategoryName . RemoveFromEnd ( TEXT ( " _C " ) ) ;
IDetailCategoryBuilder & CategoryBuilder = DetailBuilder . EditCategory ( Object - > GetClass ( ) - > GetFName ( ) , FText : : FromString ( FName : : NameToDisplayString ( CategoryName , false ) ) ) ; // TODO: Category FName should be FullName for non-native objects
// TODO: Apply property categories as sub-categories?
UClass * BaseClass = Object - > GetClass ( ) ;
while ( BaseClass )
{
for ( FProperty * Property : TFieldRange < FProperty > ( BaseClass , EFieldIteratorFlags : : ExcludeSuper , EFieldIteratorFlags : : ExcludeDeprecated ) )
{
if ( Property - > HasAnyPropertyFlags ( CPF_Config ) )
{
CategoryBuilder . AddProperty ( Property - > GetFName ( ) , BaseClass ) ;
}
}
BaseClass = BaseClass ! = T : : StaticClass ( ) ? BaseClass - > GetSuperClass ( ) : nullptr ; // Stop searching at the base type. We don't care about configurable properties lower than that.
}
}
}
} ;
template < typename T >
TSharedPtr < IDetailsView > FInputEditorModule : : AddClassDetailsView ( )
{
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
2020-11-16 09:13:23 -04:00
FDetailsViewArgs DetailsViewArgs ;
DetailsViewArgs . NameAreaSettings = FDetailsViewArgs : : HideNameArea ;
DetailsViewArgs . bHideSelectionTip = true ;
2020-09-24 00:43:27 -04:00
DetailsViewArgs . bAllowMultipleTopLevelObjects = true ;
DetailsViewArgs . bShowOptions = false ;
DetailsViewArgs . bShowPropertyMatrixButton = false ;
TSharedPtr < IDetailsView > DetailsView = PropertyEditorModule . CreateDetailView ( DetailsViewArgs ) ;
DetailsView - > OnFinishedChangingProperties ( ) . AddRaw ( this , & FInputEditorModule : : OnSettingChanged ) ;
DetailsView - > RegisterInstancedCustomPropertyLayout ( T : : StaticClass ( ) , FOnGetDetailCustomizationInstance : : CreateLambda ( & MakeShared < FPerCDOSettingsCustomization < T > > ) ) ;
// Init CDOs for view
DetailsView - > SetObjects ( GatherClassDetailsCDOs ( T : : StaticClass ( ) , nullptr ) ) ;
return DetailsViews . Add ( T : : StaticClass ( ) , DetailsView ) ;
}
TArray < UObject * > FInputEditorModule : : GatherClassDetailsCDOs ( UClass * Class , const FAssetData * IgnoreAsset )
{
TArray < UObject * > CDOs ;
// Search native classes
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
if ( ! ClassIt - > IsNative ( ) | | ! ClassIt - > IsChildOf ( Class ) )
{
continue ;
}
// Ignore abstract, hidedropdown, and deprecated.
if ( ClassIt - > HasAnyClassFlags ( CLASS_Abstract | CLASS_HideDropDown | CLASS_Deprecated | CLASS_NewerVersionExists ) )
{
continue ;
}
CDOs . AddUnique ( ClassIt - > GetDefaultObject ( ) ) ;
}
// Search BPs via asset registry
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( FName ( " AssetRegistry " ) ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
FARFilter Filter ;
Filter . ClassNames . Add ( UBlueprint : : StaticClass ( ) - > GetFName ( ) ) ;
Filter . bRecursiveClasses = true ;
TArray < FAssetData > BlueprintAssetData ;
AssetRegistry . GetAssets ( Filter , BlueprintAssetData ) ;
for ( FAssetData & Asset : BlueprintAssetData )
{
if ( IgnoreAsset & & Asset = = * IgnoreAsset )
{
continue ;
}
FAssetDataTagMapSharedView : : FFindTagResult Result = Asset . TagsAndValues . FindTag ( TEXT ( " NativeParentClass " ) ) ;
if ( Result . IsSet ( ) )
{
const FString ClassObjectPath = FPackageName : : ExportTextPathToObjectPath ( Result . GetValue ( ) ) ;
const FString ClassName = FPackageName : : ObjectPathToObjectName ( ClassObjectPath ) ;
if ( UClass * ParentClass = FindObjectSafe < UClass > ( ANY_PACKAGE , * ClassName , true ) )
{
if ( ParentClass - > IsChildOf ( Class ) )
{
// TODO: Forcibly loading these assets could cause problems on projects with a large number of them.
UBlueprint * BP = CastChecked < UBlueprint > ( Asset . GetAsset ( ) ) ;
CDOs . AddUnique ( BP - > GeneratedClass - > GetDefaultObject ( ) ) ;
}
}
}
}
// Strip objects with no config stored properties
CDOs . RemoveAll ( [ Class ] ( UObject * Object ) {
UClass * ObjectClass = Object - > GetClass ( ) ;
if ( ObjectClass - > GetMetaData ( TEXT ( " NotInputConfigurable " ) ) . ToBool ( ) )
{
return true ;
}
while ( ObjectClass )
{
for ( FProperty * Property : TFieldRange < FProperty > ( ObjectClass , EFieldIteratorFlags : : ExcludeSuper , EFieldIteratorFlags : : ExcludeDeprecated ) )
{
if ( Property - > HasAnyPropertyFlags ( CPF_Config ) )
{
return false ;
}
}
ObjectClass = ObjectClass ! = Class ? ObjectClass - > GetSuperClass ( ) : nullptr ; // Stop searching at the base type. We don't care about configurable properties lower than that.
}
return true ;
} ) ;
return CDOs ;
}
2021-05-26 20:29:20 -04:00
void FInputEditorModule : : PostEngineInit ( )
{
// Register input settings
ISettingsModule * SettingsModule = FModuleManager : : GetModulePtr < ISettingsModule > ( " Settings " ) ;
if ( SettingsModule & & FSlateApplication : : IsInitialized ( ) )
{
SettingsModule - > RegisterSettings ( " Project " , " Plugins " , " EnhancedInput " ,
LOCTEXT ( " EnhancedInputSettingsName " , " Enhanced Input " ) ,
LOCTEXT ( " EnhancedInputSettingsDescription " , " Modify defaults for configurable triggers and modifiers. " ) ,
CreateSettingsPanel ( )
) ;
}
}
2020-09-24 00:43:27 -04:00
TSharedRef < SWidget > FInputEditorModule : : CreateSettingsPanel ( )
{
TSharedPtr < IDetailsView > TriggerDetailsView = AddClassDetailsView < UInputTrigger > ( ) ;
TSharedPtr < IDetailsView > ModifierDetailsView = AddClassDetailsView < UInputModifier > ( ) ;
FSlateFontInfo HeaderFont = FEditorStyle : : GetFontStyle ( " DetailsView.CategoryFontStyle " ) ;
HeaderFont . Size = 32 ;
SAssignNew ( Panel , SScrollBox )
+ SScrollBox : : Slot ( )
. Padding ( 0.f , 4.f , 0.f , 4.f )
[
SNew ( STextBlock )
. Font ( HeaderFont )
. Text ( LOCTEXT ( " EngineInputSettingsTriggers " , " Trigger Defaults " ) )
]
+ SScrollBox : : Slot ( )
. Padding ( 0.f , 4.f , 0.f , 0.f )
[
TriggerDetailsView . ToSharedRef ( )
]
+ SScrollBox : : Slot ( )
. Padding ( 0.f , 12.f , 0.f , 4.f )
[
SNew ( STextBlock )
. Font ( HeaderFont )
. Text ( LOCTEXT ( " EngineInputSettingsModifiers " , " Modifier Defaults " ) )
]
+ SScrollBox : : Slot ( )
. Padding ( 0.f , 8.f , 0.f , 0.f )
[
ModifierDetailsView . ToSharedRef ( )
] ;
return Panel . ToSharedRef ( ) ;
}
void FInputEditorModule : : StartupModule ( )
{
// Register customizations
FPropertyEditorModule & PropertyModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
PropertyModule . RegisterCustomClassLayout ( " InputMappingContext " , FOnGetDetailCustomizationInstance : : CreateStatic ( & FInputContextDetails : : MakeInstance ) ) ;
PropertyModule . RegisterCustomPropertyTypeLayout ( " EnhancedActionKeyMapping " , FOnGetPropertyTypeCustomizationInstance : : CreateStatic ( & FEnhancedActionMappingCustomization : : MakeInstance ) ) ;
PropertyModule . NotifyCustomizationModuleChanged ( ) ;
// Register input assets
IAssetTools & AssetTools = FModuleManager : : LoadModuleChecked < FAssetToolsModule > ( " AssetTools " ) . Get ( ) ;
InputAssetsCategory = AssetTools . RegisterAdvancedAssetCategory ( FName ( TEXT ( " Input " ) ) , LOCTEXT ( " InputAssetsCategory " , " Input " ) ) ;
{
RegisterAssetTypeActions ( AssetTools , MakeShareable ( new FAssetTypeActions_InputAction ) ) ;
RegisterAssetTypeActions ( AssetTools , MakeShareable ( new FAssetTypeActions_InputContext ) ) ;
2022-01-27 14:09:11 -05:00
RegisterAssetTypeActions ( AssetTools , MakeShareable ( new FAssetTypeActions_PlayerMappableInputConfig ) ) ;
2020-09-24 00:43:27 -04:00
// TODO: Build these off a button on the InputContext Trigger/Mapping pickers? Would be good to have both.
//RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_InputTrigger));
//RegisterAssetTypeActions(AssetTools, MakeShareable(new FAssetTypeActions_InputModifier));
}
// Support for updating blueprint based triggers and modifiers in the settings panel
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( FName ( " AssetRegistry " ) ) ;
IAssetRegistry & AssetRegistry = AssetRegistryModule . Get ( ) ;
AssetRegistry . OnAssetAdded ( ) . AddRaw ( this , & FInputEditorModule : : OnAssetAdded ) ;
AssetRegistry . OnAssetRemoved ( ) . AddRaw ( this , & FInputEditorModule : : OnAssetRemoved ) ;
AssetRegistry . OnAssetRenamed ( ) . AddRaw ( this , & FInputEditorModule : : OnAssetRenamed ) ;
// TODO: Update settings whenever a config variable is added/removed to an asset
2021-05-26 20:29:20 -04:00
FCoreDelegates : : OnPostEngineInit . AddRaw ( this , & FInputEditorModule : : PostEngineInit ) ;
2020-09-24 00:43:27 -04:00
}
void FInputEditorModule : : ShutdownModule ( )
{
// Unregister settings panel listeners
if ( FAssetRegistryModule * AssetRegistryModule = FModuleManager : : GetModulePtr < FAssetRegistryModule > ( " AssetRegistry " ) )
{
AssetRegistryModule - > Get ( ) . OnAssetAdded ( ) . RemoveAll ( this ) ;
AssetRegistryModule - > Get ( ) . OnAssetRemoved ( ) . RemoveAll ( this ) ;
AssetRegistryModule - > Get ( ) . OnAssetRenamed ( ) . RemoveAll ( this ) ;
}
// Unregister input assets
if ( FAssetToolsModule * AssetToolsModule = FModuleManager : : GetModulePtr < FAssetToolsModule > ( " AssetTools " ) )
{
for ( TSharedPtr < IAssetTypeActions > & AssetAction : CreatedAssetTypeActions )
{
AssetToolsModule - > Get ( ) . UnregisterAssetTypeActions ( AssetAction . ToSharedRef ( ) ) ;
}
}
CreatedAssetTypeActions . Empty ( ) ;
// Unregister input settings
2020-10-22 19:19:16 -04:00
if ( ISettingsModule * SettingsModule = FModuleManager : : GetModulePtr < ISettingsModule > ( " Settings " ) )
{
SettingsModule - > UnregisterSettings ( " Project " , " Engine " , " Enhanced Input " ) ;
}
2020-09-24 00:43:27 -04:00
// Unregister customizations
FPropertyEditorModule & PropertyModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
PropertyModule . UnregisterCustomClassLayout ( " InputContext " ) ;
PropertyModule . UnregisterCustomPropertyTypeLayout ( " EnhancedActionKeyMapping " ) ;
PropertyModule . NotifyCustomizationModuleChanged ( ) ;
2021-05-26 20:29:20 -04:00
FCoreDelegates : : OnPostEngineInit . RemoveAll ( this ) ;
2020-09-24 00:43:27 -04:00
}
FInputEditorModule : : FClassDetailsView FInputEditorModule : : FindClassDetailsViewForAsset ( const FAssetData & AssetData )
{
if ( AssetData . AssetClass = = UBlueprint : : StaticClass ( ) - > GetFName ( ) )
{
FAssetDataTagMapSharedView : : FFindTagResult Result = AssetData . TagsAndValues . FindTag ( TEXT ( " NativeParentClass " ) ) ;
if ( Result . IsSet ( ) )
{
const FString ClassObjectPath = FPackageName : : ExportTextPathToObjectPath ( Result . GetValue ( ) ) ;
const FString ClassName = FPackageName : : ObjectPathToObjectName ( ClassObjectPath ) ;
if ( UClass * ParentClass = FindObjectSafe < UClass > ( ANY_PACKAGE , * ClassName , true ) )
{
if ( TSharedPtr < IDetailsView > * DetailsView = DetailsViews . Find ( ParentClass ) )
{
return FClassDetailsView ( ParentClass , * DetailsView ) ;
}
}
}
}
return FClassDetailsView ( ) ;
}
void FInputEditorModule : : RebuildDetailsViewForAsset ( const FAssetData & AssetData , bool bIgnoreAsset )
{
FClassDetailsView CDV = FindClassDetailsViewForAsset ( AssetData ) ;
if ( CDV . IsValid ( ) )
{
CDV . View - > SetObjects ( GatherClassDetailsCDOs ( CDV . Class , bIgnoreAsset ? & AssetData : nullptr ) ) ;
}
}
void FInputEditorModule : : Tick ( float DeltaTime )
{
// Update any blueprints that are referencing an input action with a modified value type
if ( UInputAction : : ActionsWithModifiedValueTypes . Num ( ) )
{
TSet < UBlueprint * > BPsModified ;
for ( TObjectIterator < UK2Node_EnhancedInputAction > NodeIt ; NodeIt ; + + NodeIt )
{
if ( UInputAction : : ActionsWithModifiedValueTypes . Contains ( NodeIt - > InputAction ) )
{
NodeIt - > ReconstructNode ( ) ;
BPsModified . Emplace ( NodeIt - > GetBlueprint ( ) ) ;
}
}
for ( TObjectIterator < UK2Node_GetInputActionValue > NodeIt ; NodeIt ; + + NodeIt )
{
if ( UInputAction : : ActionsWithModifiedValueTypes . Contains ( NodeIt - > InputAction ) )
{
NodeIt - > ReconstructNode ( ) ;
BPsModified . Emplace ( NodeIt - > GetBlueprint ( ) ) ;
}
}
if ( BPsModified . Num ( ) )
{
FNotificationInfo Info ( FText : : Format ( LOCTEXT ( " ActionValueTypeChange " , " Changing action value type affected {0} blueprint(s) ! " ), BPsModified.Num())) ;
Info . ExpireDuration = 5.0f ;
FSlateNotificationManager : : Get ( ) . AddNotification ( Info ) ;
}
UInputAction : : ActionsWithModifiedValueTypes . Reset ( ) ;
}
}
# undef LOCTEXT_NAMESPACE