// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "NiagaraShared.h" #include "NiagaraCommon.h" #include "Logging/TokenizedMessage.h" #include "TickableEditorObject.h" #include "UObject/ObjectKey.h" #include "Templates/SharedPointer.h" #include "NiagaraMessages.h" class FNiagaraScriptToolkit; //Extension of message token to allow opening the asset editor when clicking on the linked asset name. class FNiagaraCompileEventToken : public IMessageToken { public: /** Factory method, tokens can only be constructed as shared refs */ static TSharedRef Create( const FString& InScriptAssetPath , const FText& InMessage , const TOptional& InNodeGUID = TOptional() , const TOptional& InPinGUID = TOptional() ); /** Begin IMessageToken interface */ virtual EMessageToken::Type GetType() const override { return EMessageToken::AssetName; } /** End IMessageToken interface */ private: /** Private constructor */ FNiagaraCompileEventToken( const FString& InScriptAssetPath , const FText& InMessage , const TOptional& InNodeGUID , const TOptional& InPinGUID ); /** * Find and open an asset in editor * @param Token The token that was clicked * @param InAssetPath The asset to find */ static void OpenScriptAssetByPathAndFocusNodeOrPinIfSet( const TSharedRef& Token , FString InScriptAssetPath , const TOptional InNodeGUID , const TOptional InPinGUID ); /** The script asset path to open the editor toolkit for. */ const FString ScriptAssetPath; /** The optional Node or Pin GUID to find and focus after opening the script asset */ const TOptional NodeGUID; const TOptional PinGUID; }; class INiagaraMessageRegistrationHandle : public TSharedFromThis { public: DECLARE_DELEGATE_OneParam(FOnRequestRefresh, const TArray>& /** NewMessages*/) INiagaraMessageRegistrationHandle(const uint32 InTopicBitfield = 0) : TopicBitfield(InTopicBitfield) {}; virtual ~INiagaraMessageRegistrationHandle() = default; virtual TArray> FilterMessages(const TArray>& Messages, const uint32& DesiredTopicBitfield) const = 0; FOnRequestRefresh& GetOnRequestRefresh() { return RefreshDelegate; }; uint32 GetTopicBitfield() const { return TopicBitfield; }; protected: const uint32 TopicBitfield; FOnRequestRefresh RefreshDelegate; }; class FNiagaraMessageTopicRegistrationHandle : public INiagaraMessageRegistrationHandle { public: FNiagaraMessageTopicRegistrationHandle(const uint32 InTopicBitfield) : INiagaraMessageRegistrationHandle(InTopicBitfield) {}; virtual TArray> FilterMessages(const TArray>& Messages, const uint32& DesiredTopicBitfield) const override; }; class FNiagaraMessageObjectRegistrationHandle : public INiagaraMessageRegistrationHandle { public: FNiagaraMessageObjectRegistrationHandle(const FObjectKey& InObjectKey) : INiagaraMessageRegistrationHandle(INT32_MAX) //Pure object registrations listen for every topic , ObjectKey(InObjectKey) {}; virtual TArray> FilterMessages(const TArray>& Messages, const uint32& DesiredTopicBitfield) const override; protected: const FObjectKey ObjectKey; }; class FNiagaraMessageManager : FTickableEditorObject { public: NIAGARAEDITOR_API static FNiagaraMessageManager* Get(); NIAGARAEDITOR_API void AddMessage(const TSharedRef& InMessage, const FGuid& InMessageAssetKey); NIAGARAEDITOR_API void AddMessageJob(TUniquePtr&& InMessageJob, const FGuid& InMessageJobAssetKey); void ClearAssetMessages(const FGuid& AssetKey); void ClearAssetMessagesForTopic(const FGuid& AssetKey, const FName& Topic); void ClearAssetMessagesForObject(const FGuid& AssetKey, const FObjectKey& ObjectKeys); static const TOptional GetStringForScriptUsageInStack(const ENiagaraScriptUsage InScriptUsage); NIAGARAEDITOR_API void RegisterMessageTopic(FName TopicName); NIAGARAEDITOR_API void RegisterAdditionalMessageLogTopic(FName MessageLogTopicName); uint32 GetMessageTopicBitflag(FName TopicName); NIAGARAEDITOR_API FNiagaraMessageTopicRegistrationHandle::FOnRequestRefresh& SubscribeToAssetMessagesByTopic( const FText& DebugNameText , const FGuid& MessageAssetKey , const TArray& MessageTopics , FGuid& OutMessageManagerRegistrationKey); NIAGARAEDITOR_API FNiagaraMessageTopicRegistrationHandle::FOnRequestRefresh& SubscribeToAssetMessagesByObject( const FText& DebugNameText , const FGuid& MessageAssetKey , const FObjectKey& ObjectKey , FGuid& OutMessageManagerRegistrationKey); void Unsubscribe(const FText& DebugNameText, const FGuid& MessageAssetKey, FGuid& MessageManagerRegistrationKey); const TArray& GetAdditionalMessageLogTopics() { return AdditionalMessageLogTopics; }; //~ Begin FTickableEditorObject Interface. virtual void Tick(float DeltaSeconds) override; virtual ETickableTickType GetTickableTickType() const override { return ETickableTickType::Always; }; virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(FNiagaraMessageManager, STATGROUP_Tickables); }; //~ End FTickableEditorObject Interface private: struct FAssetMessageInfo { FAssetMessageInfo() : bDirty(false) , DirtyTopicBitfield(0) {}; TArray> Messages; TMap> RegistrationKey_To_RegistrationHandleMap; bool bDirty; uint32 DirtyTopicBitfield; }; struct FMessageJobAndAssetKey { FMessageJobAndAssetKey(const FGuid& InAssetKey) : AssetKey(InAssetKey) {}; // FMessageJobAndAssetKey(TUniquePtr&& InMessageJob, const FGuid& InAssetKey) //@todo(ng) impl // : MessageJob(MoveTemp(InMessageJob)) // , AssetKey(InAssetKey) // {}; TUniquePtr MessageJob; const FGuid AssetKey; }; FNiagaraMessageManager(); void DoMessageJobsTick(); void TryFlushMessagesTick(); void FlushMessages(); static void SetRefreshTimerElapsed(); uint32 MakeBitfieldForMessageTopics(const FText& DebugNameText, const TArray& MessageTopics); private: static constexpr double MaxJobWorkTime = .02f; // do message jobs at 50 fps. static constexpr double RefreshHysterisisTime = 2.0f; // do not consecutively request refresh subscribers more often than every 2 seconds. static bool bRefreshTimeElapsed; static bool bNeedFlushMessages; static uint32 NextTopicBitflag; // every time a topic is registered, assign this bitflag to the topic and then binary increment this bitflag. static FNiagaraMessageManager* Singleton; FTimerHandle RefreshTimerHandle; TArray MessageJobs; TMap AssetToMessageInfoMap; TMap RegisteredTopicToBitflagsMap; TArray AdditionalMessageLogTopics; };