// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "InputCoreTypes.h" #include "Templates/SubclassOf.h" #include "Templates/Casts.h" #include "Engine/EngineBaseTypes.h" #include "UObject/GCObject.h" #include "EditorWorldExtension.generated.h" struct FWorldContext; class UEditorWorldExtensionCollection; class UEditorWorldExtensionManager; class UEditorWorldExtension; class FViewport; class AActor; class FEditorViewportClient; enum class EEditorWorldExtensionTransitionState : uint8 { TransitionNone, TransitionAll, TransitionPIEOnly, TransitionNonPIEOnly }; USTRUCT() struct FEditorWorldExtensionActorData { GENERATED_BODY() UPROPERTY() TObjectPtr Actor = nullptr; UPROPERTY() bool bValidForPIE = false; }; UCLASS(MinimalAPI) class UEditorWorldExtension : public UObject { GENERATED_BODY() friend class UEditorWorldExtensionCollection; public: /** Default constructor */ UNREALED_API UEditorWorldExtension(); /** Default destructor */ UNREALED_API virtual ~UEditorWorldExtension(); /** Initialize extension */ virtual void Init() {}; /** Shut down extension when world is destroyed */ virtual void Shutdown() {}; /** Give base class the chance to tick */ virtual void Tick( float DeltaSeconds ) {}; UNREALED_API virtual bool InputKey( FEditorViewportClient* InViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event); UNREALED_API virtual bool InputAxis( FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime); /** Gets the world owning this extension */ UNREALED_API virtual UWorld* GetWorld() const override; /** Gets the world owning this extension's non-PIE valid actors when current world is a play world */ UNREALED_API virtual UWorld* GetLastEditorWorld() const; /** Spawns a transient actor that we can use in the current world of this extension (templated for convenience) */ template inline T* SpawnTransientSceneActor(const FString& ActorName, const bool bWithSceneComponent = false, const EObjectFlags InObjectFlags = EObjectFlags::RF_Transient | EObjectFlags::RF_DuplicateTransient, const bool bValidForPIE = false ) { return CastChecked(SpawnTransientSceneActor(T::StaticClass(), ActorName, bWithSceneComponent, InObjectFlags, bValidForPIE)); } /** Spawns a transient actor that we can use in the current world of this extension */ UNREALED_API AActor* SpawnTransientSceneActor(TSubclassOf ActorClass, const FString& ActorName, const bool bWithSceneComponent = false, const EObjectFlags InObjectFlags = EObjectFlags::RF_Transient | EObjectFlags::RF_DuplicateTransient, const bool bValidForPIE = false); /** Destroys a transient actor we created earlier */ UNREALED_API void DestroyTransientActor(AActor* Actor); /** Sets if this extension should be ticked. */ UNREALED_API void SetActive(const bool bInActive); /** If this extension is currently being ticked. */ UNREALED_API bool IsActive() const; /** Get the owning collection of extensions */ UNREALED_API UEditorWorldExtensionCollection* GetOwningCollection(); /** Executes command */ UNREALED_API bool ExecCommand(const FString& InCommand); protected: /** Reparent actors to a new world */ UNREALED_API virtual void TransitionWorld(UWorld* NewWorld, EEditorWorldExtensionTransitionState TransitionState); /** Give child class a chance to act on entering simulate mode */ virtual void EnteredSimulateInEditor() {}; /** Give child class a chance to act on leaving simulate mode */ virtual void LeftSimulateInEditor(UWorld* SimulateWorld) {}; /** The collection of extensions that is owning this extension */ UEditorWorldExtensionCollection* OwningExtensionsCollection; private: /** Reparent the actors to a new world. */ UNREALED_API void ReparentActor(AActor* Actor, UWorld* NewWorld); /** Let the FEditorWorldExtensionCollection set the world of this extension before init */ UNREALED_API void InitInternal(UEditorWorldExtensionCollection* InOwningExtensionsCollection); UPROPERTY() TArray ExtensionActors; /** If this extension is currently being ticked */ bool bActive; }; /** * Holds a collection of UEditorExtension */ UCLASS(MinimalAPI) class UEditorWorldExtensionCollection : public UObject { GENERATED_BODY() friend class UEditorWorldExtensionManager; public: /** Default constructor */ UNREALED_API UEditorWorldExtensionCollection(); /** Default destructor */ UNREALED_API virtual ~UEditorWorldExtensionCollection(); /** Gets the world from the world context */ UNREALED_API virtual UWorld* GetWorld() const override; /** Gets the last editor world, will only be non-null when current world is a play world. */ UNREALED_API UWorld* GetLastEditorWorld() const; /** * Checks if the passed extension already exists and creates one if it doesn't. * @param EditorExtensionClass the subclass of an extension to create if necessary and add. */ UNREALED_API UEditorWorldExtension* AddExtension(TSubclassOf EditorExtensionClass); /** * Adds an extension to the collection * @param EditorExtension The UEditorExtension that will be created, initialized and added to the collection. */ UNREALED_API void AddExtension( UEditorWorldExtension* EditorExtension ); /** * Removes an extension from the collection and calls Shutdown() on the extension * @param EditorExtension The UEditorExtension to remove. It must already have been added. */ UNREALED_API void RemoveExtension( UEditorWorldExtension* EditorExtension ); /** * Find an extension based on the class * @param EditorExtensionClass The class to find an extension with * @return The first extension that is found based on class */ UNREALED_API UEditorWorldExtension* FindExtension( TSubclassOf EditorExtensionClass ); /** Ticks all extensions */ UNREALED_API void Tick( float DeltaSeconds ); /** Notifies all extensions of keyboard input */ UNREALED_API bool InputKey( FEditorViewportClient* InViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event); /** Notifies all extensions of axis movement */ UNREALED_API bool InputAxis( FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime); /** Show or hide all the actors of extensions that belong to this collection. */ UNREALED_API void ShowAllActors(const bool bShow); private: /** Sets the world for this collection and gives every extension an opportunity to transition */ UNREALED_API void SetWorld(UWorld* NewWorld, EEditorWorldExtensionTransitionState TransitionState /* = EEditorWorldExtensionTransitionState::TransitionAll */); /** Transitions actors in every extension to the specified world */ UNREALED_API void TransitionWorld(UWorld* NewWorld, EEditorWorldExtensionTransitionState TransitionState); /** Called by the editor after PIE or Simulate is started */ UNREALED_API void PostPIEStarted( bool bIsSimulatingInEditor ); /** Called just before PIE or Simulate ends */ UNREALED_API void OnPreEndPIE(bool bWasSimulatingInEditor); /** Called when PIE or Simulate ends */ UNREALED_API void OnEndPIE( bool bWasSimulatingInEditor ); /** Called when switching between play and simulate */ UNREALED_API void SwitchPIEAndSIE(bool bIsSimulatingInEditor); /** World context */ TWeakObjectPtr Currentworld; /** After entering Simulate or PIE, this stores the counterpart editor world to the play world, so that we know this collection needs to transition back to editor world after Simulate or PIE finishes. */ TWeakObjectPtr LastEditorWorld; /** List of extensions along with their reference count. Extensions will only be truly removed and Shutdown() after their reference count drops to zero. */ typedef TTuple FEditorExtensionTuple; TArray EditorExtensions; }; /** * Holds a map of extension collections paired with worlds */ UCLASS(MinimalAPI) class UEditorWorldExtensionManager : public UObject { GENERATED_BODY() public: /** Default constructor */ UNREALED_API UEditorWorldExtensionManager(); /** Default destructor */ UNREALED_API virtual ~UEditorWorldExtensionManager(); /** Gets the editor world wrapper that is found with the world passed. * Adds one for this world if there was non found. */ UNREALED_API UEditorWorldExtensionCollection* GetEditorWorldExtensions(UWorld* InWorld, const bool bCreateIfNeeded = true); /** Ticks all the collections */ UNREALED_API void Tick( float DeltaSeconds ); private: /** Adds a new editor world wrapper when a new world context was created */ UEditorWorldExtensionCollection* OnWorldAdd(UWorld* World); /** Adds a new editor world wrapper when a new world context was created */ void OnWorldContextRemove(FWorldContext& InWorldContext); UEditorWorldExtensionCollection* FindExtensionCollection(const UWorld* InWorld); /** Map of all the editor world maps */ UPROPERTY() TArray> EditorWorldExtensionCollection; };