Files
UnrealEngine/Engine/Plugins/MetaHuman/MetaHumanCharacter/Source/MetaHumanCharacterPalette/Public/MetaHumanCollection.h
2025-05-18 13:04:45 +08:00

255 lines
9.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "MetaHumanCharacterPalette.h"
#include "MetaHumanCharacterEditorPipeline.h"
#include "MetaHumanPinnedSlotSelection.h"
#include "MetaHumanCollection.generated.h"
class UMetaHumanCollectionPipeline;
class UMetaHumanCollectionEditorPipeline;
#if WITH_EDITORONLY_DATA
UENUM()
enum class EMetaHumanCharacterUnpackPathMode : uint8
{
/**
* Assets will be unpacked to a subfolder of the Palette's current folder.
* The subfolder will have the same name as the Palette.
*
* For example, when a Palette called A is at path /Game/Palettes, its assets
* would be unpacked to the /Game/Palettes/A folder.
*/
SubfolderNamedForPalette UMETA(Hidden),
/** UnpackFolderPath is a relative path from the folder containing the Palette */
Relative,
/** UnpackFolderPath is an absolute path */
Absolute
};
UENUM()
enum class EMetaHumanCharacterAssetsUnpackResult : uint8
{
Succeeded,
Failed
};
DECLARE_DELEGATE_OneParam(FOnMetaHumanCharacterAssetsUnpacked, EMetaHumanCharacterAssetsUnpackResult /* Result */);
#endif
/** The output of the Character Pipeline's build step for a specific platform */
USTRUCT()
struct METAHUMANCHARACTERPALETTE_API FMetaHumanCollectionBuiltData
{
GENERATED_BODY()
public:
/** Returns true if this built data has been populated from a successful build */
bool IsValid() const;
UPROPERTY()
FMetaHumanPaletteBuiltData PaletteBuiltData;
UPROPERTY()
TArray<FMetaHumanPinnedSlotSelection> SortedPinnedSlotSelections;
/** The level of quality this data was built for */
UPROPERTY()
EMetaHumanCharacterPaletteBuildQuality Quality = EMetaHumanCharacterPaletteBuildQuality::Production;
};
/**
* A collection of character parts (e.g. MetaHuman Characters, clothing, hairstyles) that target
* slots on a Character Pipeline.
*
* Create a Character Instance from a Collection to assemble a renderable character from the parts
* contained in the Collection.
*/
UCLASS(BlueprintType)
class METAHUMANCHARACTERPALETTE_API UMetaHumanCollection : public UMetaHumanCharacterPalette
{
GENERATED_BODY()
public:
DECLARE_MULTICAST_DELEGATE_OneParam(FOnPaletteBuilt, EMetaHumanCharacterPaletteBuildQuality /* Quality */);
DECLARE_MULTICAST_DELEGATE(FOnPipelineChanged);
UMetaHumanCollection();
// Collections should not be created or modified outside the editor
#if WITH_EDITOR
DECLARE_DELEGATE_OneParam(FOnBuildComplete, EMetaHumanBuildStatus /* Status */);
/** Builds the collection so that Character Instances can assemble characters from it */
void Build(
const FInstancedStruct& BuildInput,
EMetaHumanCharacterPaletteBuildQuality Quality,
ITargetPlatform* TargetPlatform,
const FOnBuildComplete& OnComplete,
const TArray<FMetaHumanPinnedSlotSelection>& PinnedSlotSelections = TArray<FMetaHumanPinnedSlotSelection>(),
const TArray<FMetaHumanPaletteItemPath>& ItemsToExclude = TArray<FMetaHumanPaletteItemPath>());
/**
* Moves any built assets stored within this Collection to their own asset packages, making them
* standalone assets that can be referenced from other objects.
*
* The Collection can still be used as normal after this, as it will still reference the unpacked
* assets as it did before they were unpacked.
*/
void UnpackAssets(const FOnMetaHumanCharacterAssetsUnpacked& OnComplete = FOnMetaHumanCharacterAssetsUnpacked());
/**
* Sets the default Pipeline from the project settings.
*
* Call this after constructing a Collection if you don't have a specific Pipeline to use.
*/
void SetDefaultPipeline();
/**
* Set the Pipeline for this Collection to use.
*
* It's not necessary to provide each Collection instance with a unique Pipeline instance, as the
* Pipeline is intended to be stateless. However, the Pipeline instance will be editable in
* Details panels wherever the Collection is visible for editing, and users editing a Pipeline's
* properties from there may be surprised if these edits affect other Collections.
*/
void SetPipeline(TNotNull<UMetaHumanCollectionPipeline*> InPipeline);
/**
* Sets the Pipeline to be an instance of the given class
*/
void SetPipelineFromClass(TSubclassOf<UMetaHumanCollectionPipeline> InPipelineClass);
/** Convenience function to access the editor pipeline */
const UMetaHumanCollectionEditorPipeline* GetEditorPipeline() const;
virtual const UMetaHumanCharacterEditorPipeline* GetPaletteEditorPipeline() const override;
#endif
/**
* The Pipeline targeted by this Collection.
*
* May be null if the user hasn't set a pipeline yet.
*/
UMetaHumanCollectionPipeline* GetMutablePipeline();
/**
* The Pipeline targeted by this Collection.
*
* May be null if the user hasn't set a pipeline yet.
*/
const UMetaHumanCollectionPipeline* GetPipeline() const;
virtual const UMetaHumanCharacterPipeline* GetPalettePipeline() const override;
/** Note that the returned data is not guaranteed to be valid. Call IsValid on the result to check. */
const FMetaHumanCollectionBuiltData& GetBuiltData(EMetaHumanCharacterPaletteBuildQuality Quality) const;
/**
* The Collection contains a default instance that is used for preview.
*
* The default instance is a valid instance in its own right and can be used at runtime.
*
* Guaranteed to be non-null.
*/
TNotNull<UMetaHumanCharacterInstance*> GetMutableDefaultInstance();
TNotNull<const UMetaHumanCharacterInstance*> GetDefaultInstance() const;
#if WITH_EDITORONLY_DATA
void SetBuiltData(EMetaHumanCharacterPaletteBuildQuality Quality, FMetaHumanCollectionBuiltData&& Data);
#endif // WITH_EDITORONLY_DATA
#if WITH_EDITOR
// Begin UObject interface
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
// End UObject interface
#endif // WITH_EDITOR
/**
* Resolves virtual slots in the given array of selections.
*
* For each selection in the array, if that selection targets a virtual slot, it will be
* updated to target the underlying real slot.
*
* Once this is done, code using the resulting array can just operate on real slots and doesn't
* have to handle virtual slots at all.
*
* This function assumes that PipelineSpec is valid (i.e. PipelineSpec->IsValid() returns true),
* otherwise it may assert or never return.
*
* Any selections that don't resolve to valid items in the Collection will be omitted from the
* returned array.
*/
[[nodiscard]] TArray<FMetaHumanPipelineSlotSelectionData> PropagateVirtualSlotSelections(const TArray<FMetaHumanPipelineSlotSelectionData>& Selections) const;
#if WITH_EDITOR
/**
* Delegate fired when a new Pipeline has been set on this Collection.
*
* This can only happen in editor.
*
* If any changes need to be made to the Collection in response to the Pipeline changing, such as
* removing items from slots that don't exist on the new Pipeline, those changes will be made
* before this delegate is fired.
*/
FOnPipelineChanged OnPipelineChanged;
#endif // WITH_EDITOR
#if WITH_EDITORONLY_DATA
/** The mode for determining which folder to unpack the Collection's assets to */
UPROPERTY(EditAnywhere, Category = "Targets", DisplayName = "Root Relative", meta = (Tooltip = "The mode for determining whether the Root path is relative to the character asset path"))
EMetaHumanCharacterUnpackPathMode UnpackPathMode = EMetaHumanCharacterUnpackPathMode::Relative;
/** The folder path that assets will be unpacked to. Interpreted according to UnpackPathMode. */
UPROPERTY(EditAnywhere, Category = "Targets", DisplayName = "Root Path", meta = (EditCondition = "UnpackPathMode != EMetaHumanCharacterUnpackPathMode::SubfolderNamedForPalette", EditConditionHides, Tooltip = "Project directory to place the generated assets"))
FString UnpackFolderPath;
/** Returns the folder path where the assets will be unpacked, depending on the UnpackPathMode */
FString GetUnpackFolder() const;
#endif // WITH_EDITORONLY_DATA
/** Delegate fired when the Collection has finished building, if it succeeded */
FOnPaletteBuilt OnPaletteBuilt;
private:
/** The MetaHuman Collection Pipeline used to build this collection */
UPROPERTY(EditAnywhere, Instanced, Category = "Character")
TObjectPtr<UMetaHumanCollectionPipeline> Pipeline;
UPROPERTY()
TObjectPtr<UMetaHumanCharacterInstance> DefaultInstance;
UPROPERTY()
FMetaHumanCollectionBuiltData ProductionBuiltData;
#if WITH_EDITORONLY_DATA
/**
* Built data from Preview quality builds.
*
* Should be recreated as needed for preview. Shouldn't be saved or copied.
*/
UPROPERTY(Transient, DuplicateTransient)
FMetaHumanCollectionBuiltData PreviewBuiltData;
/**
* A per-item cache that persists between builds.
*
* There is not guaranteed to be an entry for every item.
*/
UPROPERTY()
TMap<FMetaHumanPaletteItemPath, FMetaHumanPaletteBuildCacheEntry> ItemBuildCache;
UPROPERTY()
FMetaHumanPaletteBuildCacheEntry PaletteBuildCache;
#endif // WITH_EDITORONLY_DATA
/** True if the assets in this Collection have been unpacked and are in their own packages. */
UPROPERTY()
bool bIsUnpacked;
};