// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MassArchetypeTypes.h" #include "MassEntityQuery.h" #include "MassProcessorDependencySolver.h" #include "MassProcessingTypes.h" #include "MassProcessor.h" #include "Types/SlateEnums.h" #include "MassDebugger.h" class FJsonObject; class UMassProcessor; struct FMassArchetypeHandle; struct FMassDebuggerModel; struct FMassEntityHandle; struct FMassEntityManager; struct FMassEntityQuery; class UWorld; class SMassEntitiesView; class SMassDebugger; namespace UE::MassDebugger { class SQueryEditorView; /** A serializable wrapper for a fragment type and access method used for editable queries */ struct FFragmentEntry { /** Convert this struct to a Json object */ TSharedPtr SerializeToJson() const; /** Populate this struct from a Json object created with the above Serialize method */ bool DeserializeFromJson(const TSharedPtr& JsonObject); /** Parse Json string then serialize from that (paste) */ bool DeserializeFromJsonString(const FString& JsonString); /** The current struct type (selected in the editor combo box) */ TWeakObjectPtr StructType; /** Access mode for this fragment entry in a query (not used for tags) */ EMassFragmentAccess AccessMode = EMassFragmentAccess::ReadOnly; /** Presense requred for this fragment in a query */ EMassFragmentPresence Presence = EMassFragmentPresence::All; /** Used to hide access mode when unused (e.g. with tags) */ bool bShowAccessMode = true; }; /** A serializable and editable representation of a FMassEntityQuery */ struct FEditableQuery { /** * Convert this entire object and it FragmentEntry arrays to Json * Used to save user queries created in the debugger UI */ TSharedPtr SerializeToJson() const; /** * Deserialize Json object hierarchy and populate this struct * Used to load saved user queries when opening the debugger */ bool DeserializeFromJson(const TSharedPtr& JsonObject); /** * Parse the Json string then deserialize * Used to paste queries in the debugger */ bool DeserializeFromJsonString(const FString& JsonString); /** * Create an editable query from a runtime query struct * Used to view/edit and use runtime queries (e.g. on a Processor) in the editor */ void InitFromEntityQuery(const FMassEntityQuery& InQuery, FMassDebuggerModel& DebuggerModel); /** The visible/editable name of the query */ FString Name; /** Editable representation of the fragment requirements for the query */ TArray> FragmentRequirements; /** Editable representation of the tag requirements for the query */ TArray> TagRequirements; /** * Create a usable runtime query from this editable query * Used by the debugger to manually run entity queries or for breakpoints */ FMassEntityQuery BuildEntityQuery(const TSharedRef EntityManager); }; } // namespace UE::MassDebugger enum class EMassDebuggerSelectionMode : uint8 { None, Processor, Archetype, // @todo future: // Fragment MAX }; enum class EMassDebuggerProcessorSelection : uint8 { None, Selected, MAX }; enum class EMassDebuggerProcessingGraphNodeSelection : uint8 { None, WaitFor, Block, MAX }; struct FMassDebuggerQueryData { FMassDebuggerQueryData(const FMassEntityQuery& Query, const FText& InLabel); FMassDebuggerQueryData(const FMassSubsystemRequirements& SubsystemRequirements, const FText& InLabel); FMassExecutionRequirements ExecutionRequirements; FText Label; FText AdditionalInformation; FMassEntityQuery SourceQuery; int32 GetTotalBitsUsedCount(); bool IsEmpty() const; }; struct FMassDebuggerArchetypeData { FMassDebuggerArchetypeData(const FMassArchetypeHandle& ArchetypeHandle); FMassArchetypeHandle Handle; FMassArchetypeCompositionDescriptor Composition; /** Hash of the Compositions. */ uint32 CompositionHash = 0; /** Combined hash of composition and shared fragments. */ uint32 FullHash = 0; /** Archetype statistics */ UE::Mass::Debug::FArchetypeStats ArchetypeStats; /** Child debugger data (same as parent, but changed in some way) */ TArray> Children; /** Parent debugger data. */ TWeakPtr Parent; /** Index in FMassDebuggerModel::CachedArchetypes */ int32 Index = INDEX_NONE; /** Display label */ FText Label; /** Display label */ FText LabelLong; /** Display label tooltip */ FText LabelTooltip; /** FullHash as a display string */ FText HashLabel; /** Primary debug name, used for grouping derived archetypes. */ FString PrimaryDebugName; /** True if the archetype is selected. */ bool bIsSelected = false; int32 GetTotalBitsUsedCount() const; }; struct FMassDebuggerProcessorData { FMassDebuggerProcessorData(const UMassProcessor& InProcessor); FMassDebuggerProcessorData(const FMassEntityManager& InEntityManager, const UMassProcessor& InProcessor, const TMap>& InTransientArchetypesMap); private: void SetProcessor(const UMassProcessor& InProcessor); public: FString Name; FString Label; uint32 ProcessorHash = 0; bool bIsActive = true; TWeakPtr EntityManager; TWeakObjectPtr Processor; EMassDebuggerProcessorSelection Selection = EMassDebuggerProcessorSelection::None; TSharedPtr ProcessorRequirements; TArray> Queries; TArray> ValidArchetypes; #if WITH_MASSENTITY_DEBUG FString Description; #endif // WITH_MASSENTITY_DEBUG }; struct FMassDebuggerFragmentData { FMassDebuggerFragmentData(TNotNull InFragment); bool operator==(const FMassDebuggerFragmentData& Other) const { return Fragment == Other.Fragment; } friend uint32 GetTypeHash(const FMassDebuggerFragmentData& Item) { return GetTypeHash(Item.Fragment); } FText Name; TWeakObjectPtr Fragment; TWeakPtr EntityManager; TArray Archetypes; TArray> Processors; int32 NumEntities = 0; }; struct FMassDebuggerBreakpointData { FMassDebuggerBreakpointData() = default; FMassDebuggerBreakpointData(const UE::Mass::Debug::FBreakpoint& InBreakpoint, FMassDebuggerModel& Model); void ReconcileDataFromNames(FMassDebuggerModel& Model); void ReconcileDataFromEngineBreakpoint(FMassDebuggerModel& Model); void ApplyToEngine(FMassDebuggerModel& Model, bool bRefreshEngineBreakpoints = true); TSharedPtr SerializeToJson() const; bool DeserializeFromJson(const TSharedPtr& JsonObject); bool DeserializeFromJsonString(const FString& JsonString); UE::Mass::Debug::FBreakpoint BreakpointInstance; FString TriggerName; FString FilterName; TSharedPtr TriggerFragment; TSharedPtr TriggerProcessor; TSharedPtr FilterQuery; }; struct FMassDebuggerProcessingGraphNode { explicit FMassDebuggerProcessingGraphNode(const TSharedPtr& InProcessorData, const UMassCompositeProcessor::FDependencyNode& InProcessorNode = UMassCompositeProcessor::FDependencyNode()); FText GetLabel() const; TSharedPtr ProcessorData; TArray WaitForNodes; TArray BlockNodes; EMassDebuggerProcessingGraphNodeSelection GraphNodeSelection = EMassDebuggerProcessingGraphNodeSelection::None; }; struct FMassDebuggerProcessingGraph { FMassDebuggerProcessingGraph(const FMassDebuggerModel& DebuggerModel, TNotNull InGraphOwner); FString Label; TArray GraphNodes; bool bSingleTheadGraph = !bool(MASS_DO_PARALLEL); }; struct FMassDebuggerEnvironment { explicit FMassDebuggerEnvironment(const TSharedRef& InEntityManager); bool operator==(const FMassDebuggerEnvironment& Other) const { return EntityManager == Other.EntityManager; } FString GetDisplayName() const; TSharedPtr GetEntityManager() const; TSharedPtr GetMutableEntityManager() const; bool IsWorldValid() const { return World.IsValid(); } bool NeedsValidWorld() const { return bNeedsValidWorld; } TWeakPtr EntityManager; TMap ProcessorProviders; TWeakObjectPtr World; bool bNeedsValidWorld = false; }; struct FMassDebuggerModel { DECLARE_MULTICAST_DELEGATE(FOnRefresh); DECLARE_MULTICAST_DELEGATE_TwoParams(FOnProcessorsSelected, TConstArrayView>, ESelectInfo::Type); DECLARE_MULTICAST_DELEGATE_TwoParams(FOnArchetypesSelected, TConstArrayView>, ESelectInfo::Type); DECLARE_MULTICAST_DELEGATE_OneParam(FOnFragmentSelected, FName FragmentName); DECLARE_MULTICAST_DELEGATE(FOnQueriesChanged); DECLARE_MULTICAST_DELEGATE(FOnBreakpointsChanged); FMassDebuggerModel(); ~FMassDebuggerModel(); void SetEnvironment(const TSharedPtr& Item); void RefreshAll(); void LoadQueriesFromDisk(); void SelectProcessor(TSharedPtr& Processor); void SelectProcessors(TArrayView> Processors, ESelectInfo::Type SelectInfo); void ClearProcessorSelection(); void SelectArchetypes(TArrayView> SelectedArchetypes, ESelectInfo::Type SelectInfo); void ClearArchetypeSelection(); bool IsCurrentEnvironment(const FMassDebuggerEnvironment& InEnvironment) const { return Environment && *Environment.Get() == InEnvironment; } bool IsCurrentEnvironmentValid() const { return Environment && Environment->EntityManager.IsValid(); } bool HasEnvironmentSelected() const { return static_cast(Environment); } void CacheArchetypesData(TMap>& OutTransientArchetypesMap); void CacheProcessorsData(const TMap>& InTransientArchetypesMap, TArray>& OutCompositeProcessors); void CacheProcessingGraphs(TConstArrayView> InCompositeProcessors); void CacheFragmentData( TArray>& OutData, const TConstArrayView>& FragmentTypes, bool bAppend ); void CacheFragmentData(); TSharedPtr FindFragmentData(const UScriptStruct* FragmentType); void CacheTagData(); void LoadBreakpointsFromDisk(); void SaveBreakpointsToDisk(); void CreateBreakpoint(); void CreateBreakpointFromString(const FString& InString); void ApplyBreakpointsToCurrentEnvironment(); void ReconcileAllBreakpoints(); void RemoveAllBreakpoints(); void RemoveBreakpoint(UE::Mass::Debug::FBreakpointHandle Handle); float MinDistanceToSelectedArchetypes(const TSharedPtr& InArchetypeData) const; FText GetDisplayName() const; void MarkAsStale(); bool IsStale() const; const TSharedPtr& GetProcessorDataChecked(const UMassProcessor& Processor) const; void RegisterEntitiesView(TSharedRef EntitiesView, int32 Index); static const int32 MaxEntityViewCount = 1; void ShowEntitiesView(int Index, FMassArchetypeHandle ArchetypeHandle); void ShowEntitiesView(int Index, TArray EntitieHandles); void ShowEntitiesView(int Index, FMassEntityQuery& Query); void ShowEntitiesView(int Index, TConstArrayView InQueries); void ResetEntitiesViews(); TWeakPtr ShowEntitiesView(int32 Index); void RegisterQueryEditor(TSharedRef InQueryEditorView); void ShowQueryInEditor(const FMassEntityQuery& InQuery, const FString& InQueryName); void RefreshQueries(); protected: void StoreArchetypes(const FMassEntityManager& EntityManager, TMap>& OutTransientArchetypesMap); void ResetSelectedArchetypes(); void ResetSelectedProcessors(); void OnEntitySelected(const FMassEntityManager& EntityManager, const FMassEntityHandle EntityHandle); void OnBreakpointsChanged(); public: TWeakPtr DebuggerWindow; FOnRefresh OnRefreshDelegate; FOnProcessorsSelected OnProcessorsSelectedDelegate; FOnArchetypesSelected OnArchetypesSelectedDelegate; FOnFragmentSelected OnFragmentSelectedDelegate; FOnBreakpointsChanged OnEditorBreakpointsChangedDelegate; FOnQueriesChanged OnQueriesChangedDelegate; EMassDebuggerSelectionMode SelectionMode = EMassDebuggerSelectionMode::None; TSharedPtr Environment; struct FProcessorCollection { FProcessorCollection(FName InLabel = FName()) : Label(InLabel) { } FName Label; TArray> Container; }; TArray> QueryList; TArray> CachedTagData; TArray> CachedFragmentData; TArray> CachedProcessorCollections; TArray> SelectedProcessors; TArray> CachedAllArchetypes; TArray> CachedArchetypeRepresentatives; TArray> SelectedArchetypes; TArray> CachedProcessingGraphs; TArray> CachedBreakpoints; /** Name lists and maps for easy lookup from widgets */ TArray> ProcessorNames; TMap> ProcessorMap; TArray> FragmentNames; TMap> FragmentMap; TArray> TagNames; TMap> TagMap; TArray> QueryNames; TMap> QueryMap; TMap> HandleToArchetypeMap; TArray> ArchetypeDistances; FString EnvironmentDisplayName; FDelegateHandle OnEntitySelectedHandle; FDelegateHandle OnBreakpointsChangedHandle; void SelectFragment(FName InFragementName); FName GetSelectedFragment(); protected: TArray> AllCachedProcessors; TArray> EntityViews; TWeakPtr QueryEditorView; FName SelectedFragmentName; public: UE_DEPRECATED(5.6, "CachedProcessors property is now deprecated. Use CachedProcessorCollections instead. ") TArray> CachedProcessors; };