Files
UnrealEngine/Engine/Plugins/Mutable/Source/CustomizableObject/Internal/MuCO/CustomizableObjectPrivate.h
2025-05-18 13:04:45 +08:00

1914 lines
50 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "MuCO/CustomizableObject.h"
#include "MuCO/CustomizableObjectCompilerTypes.h"
#include "MuCO/CustomizableObjectClothingTypes.h"
#include "MuCO/CustomizableObjectStreamedResourceData.h"
#include "MuCO/StateMachine.h"
#include "MuCO/CustomizableObjectUIData.h"
#include "MuCO/CustomizableObjectIdentifier.h"
#include "Serialization/BulkData.h"
#include "Templates/SharedPointer.h"
#include "UObject/WeakObjectPtr.h"
#include "UObject/SoftObjectPtr.h"
#include "MuR/Types.h"
#if WITH_EDITOR
#include "Misc/Guid.h"
#include "Engine/DataTable.h"
#endif
#include "CustomizableObjectPrivate.generated.h"
namespace mu
{
class FModel;
struct FBoneName;
}
#if WITH_EDITOR
namespace MutablePrivate
{
struct FClassifyNode;
}
namespace UE::DerivedData
{
struct FValueId;
struct FCacheKey;
enum class ECachePolicy : uint32;
}
#endif
class USkeletalMesh;
class USkeleton;
class UPhysicsAsset;
class UMaterialInterface;
class UTexture;
class UAnimInstance;
class UAssetUserData;
class USkeletalMeshLODSettings;
class UModelResources;
struct FModelStreamableBulkData;
struct FObjectAndNameAsStringProxyArchive;
struct FCustomizableObjectInstanceDescriptor;
FGuid CUSTOMIZABLEOBJECT_API GenerateIdentifier(const UCustomizableObject& CustomizableObject);
FString CUSTOMIZABLEOBJECT_API GetModelResourcesNameForPlatform(const UCustomizableObject& CustomizableObject, const ITargetPlatform& Platform);
// A USTRUCT version of FMeshToMeshVertData in SkeletalMeshTypes.h
// We are taking advantage of the padding data to store from which asset this data comes from
// maintaining the same memory footprint than the original.
USTRUCT()
struct FCustomizableObjectMeshToMeshVertData
{
GENERATED_USTRUCT_BODY()
FCustomizableObjectMeshToMeshVertData() = default;
explicit FCustomizableObjectMeshToMeshVertData(const FMeshToMeshVertData& Original)
: Weight(Original.Weight)
{
for (int32 i = 0; i < 4; ++i)
{
PositionBaryCoordsAndDist[i] = Original.PositionBaryCoordsAndDist[i];
NormalBaryCoordsAndDist[i] = Original.NormalBaryCoordsAndDist[i];
TangentBaryCoordsAndDist[i] = Original.TangentBaryCoordsAndDist[i];
SourceMeshVertIndices[i] = Original.SourceMeshVertIndices[i];
}
}
explicit operator FMeshToMeshVertData() const
{
FMeshToMeshVertData ReturnValue;
for (int32 i = 0; i < 4; ++i)
{
ReturnValue.PositionBaryCoordsAndDist[i] = PositionBaryCoordsAndDist[i];
ReturnValue.NormalBaryCoordsAndDist[i] = NormalBaryCoordsAndDist[i];
ReturnValue.TangentBaryCoordsAndDist[i] = TangentBaryCoordsAndDist[i];
ReturnValue.SourceMeshVertIndices[i] = SourceMeshVertIndices[i];
}
ReturnValue.Weight = Weight;
ReturnValue.Padding = 0;
return ReturnValue;
}
// Barycentric coords and distance along normal for the position of the final vert
UPROPERTY()
float PositionBaryCoordsAndDist[4] = {0.f};
// Barycentric coords and distance along normal for the location of the unit normal endpoint
// Actual normal = ResolvedNormalPosition - ResolvedPosition
UPROPERTY()
float NormalBaryCoordsAndDist[4] = {0.f};
// Barycentric coords and distance along normal for the location of the unit Tangent endpoint
// Actual normal = ResolvedNormalPosition - ResolvedPosition
UPROPERTY()
float TangentBaryCoordsAndDist[4] = {0.f};
// Contains the 3 indices for verts in the source mesh forming a triangle, the last element
// is a flag to decide how the skinning works, 0xffff uses no simulation, and just normal
// skinning, anything else uses the source mesh and the above skin data to get the final position
UPROPERTY()
uint16 SourceMeshVertIndices[4] = {0u, 0u, 0u, 0u};
UPROPERTY()
float Weight = 0.0f;
// Non serialized, unused padding. This is present in the FMeshToMeshVertData struct as Padding for alignment.
uint32 UnusedPadding = 0;
/**
* Serializer
*
* @param Ar - archive to serialize with
* @param V - vertex to serialize
* @return archive that was used
*/
friend FArchive& operator<<(FArchive& Ar, FCustomizableObjectMeshToMeshVertData& V)
{
Ar << V.PositionBaryCoordsAndDist[0];
Ar << V.PositionBaryCoordsAndDist[1];
Ar << V.PositionBaryCoordsAndDist[2];
Ar << V.PositionBaryCoordsAndDist[3];
Ar << V.NormalBaryCoordsAndDist[0];
Ar << V.NormalBaryCoordsAndDist[1];
Ar << V.NormalBaryCoordsAndDist[2];
Ar << V.NormalBaryCoordsAndDist[3];
Ar << V.TangentBaryCoordsAndDist[0];
Ar << V.TangentBaryCoordsAndDist[1];
Ar << V.TangentBaryCoordsAndDist[2];
Ar << V.TangentBaryCoordsAndDist[3];
Ar << V.SourceMeshVertIndices[0];
Ar << V.SourceMeshVertIndices[1];
Ar << V.SourceMeshVertIndices[2];
Ar << V.SourceMeshVertIndices[3];
Ar << V.Weight;
return Ar;
}
};
static_assert(sizeof(FCustomizableObjectMeshToMeshVertData) == sizeof(float)*4*3 + sizeof(uint16)*4 + sizeof(float) + sizeof(uint32));
template<> struct TCanBulkSerialize<FCustomizableObjectMeshToMeshVertData> { enum { Value = true }; };
// Warning! MutableCompiledDataHeader must be the first data serialized in a stream
struct MutableCompiledDataStreamHeader
{
int32 InternalVersion=0;
FGuid VersionId;
MutableCompiledDataStreamHeader() { }
MutableCompiledDataStreamHeader(int32 InInternalVersion, FGuid InVersionId) : InternalVersion(InInternalVersion), VersionId(InVersionId) { }
friend FArchive& operator<<(FArchive& Ar, MutableCompiledDataStreamHeader& Header)
{
Ar << Header.InternalVersion;
Ar << Header.VersionId;
return Ar;
}
};
struct FCustomizableObjectStreameableResourceId
{
enum class EType : uint8
{
None = 0,
AssetUserData = 1,
RealTimeMorphTarget = 2,
Clothing = 3,
};
uint64 Id : 64 - 8;
uint64 Type : 8;
friend bool operator==(FCustomizableObjectStreameableResourceId A, FCustomizableObjectStreameableResourceId B)
{
return BitCast<uint64>(A) == BitCast<uint64>(B);
}
};
static_assert(sizeof(FCustomizableObjectStreameableResourceId) == sizeof(uint64));
USTRUCT()
struct FMutableRemappedBone
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
FName Name;
UPROPERTY()
uint32 Hash = 0;
bool operator==(const FName& InName)
{
return Name == InName;
}
};
USTRUCT()
struct FMutableModelParameterValue
{
GENERATED_USTRUCT_BODY()
FMutableModelParameterValue() = default;
UPROPERTY()
FString Name;
UPROPERTY()
int Value = 0;
};
USTRUCT()
struct FMutableModelParameterProperties
{
GENERATED_USTRUCT_BODY()
FMutableModelParameterProperties() = default;
FString Name;
UPROPERTY()
EMutableParameterType Type = EMutableParameterType::None;
UPROPERTY()
TArray<FMutableModelParameterValue> PossibleValues;
};
class FMeshCache
{
public:
USkeletalMesh* Get(const TArray<mu::FResourceID>& Key);
void Add(const TArray<mu::FResourceID>& Key, USkeletalMesh* Value);
private:
TMap<TArray<mu::FResourceID>, TWeakObjectPtr<USkeletalMesh>> GeneratedMeshes;
};
class FSkeletonCache
{
public:
USkeleton* Get(const TArray<uint16>& Key);
void Add(const TArray<uint16>& Key, USkeleton* Value);
private:
TMap<TArray<uint16>, TWeakObjectPtr<USkeleton>> MergedSkeletons;
};
struct FCustomizableObjectStatusTypes
{
enum class EState : uint8
{
Loading = 0, // Waiting for PostLoad and Asset Registry to finish.
ModelLoaded, // Model loaded correctly.
NoModel, // No model (due to no model not found and automatic compilations disabled).
// Compiling, // Compiling the CO. Equivalent to UCustomizableObject::IsLocked = true.
Count,
};
static constexpr EState StartState = EState::NoModel;
static constexpr bool ValidTransitions[3][3] =
{
// TO
// Loading, ModelLoaded, NoModel // FROM
{false, true, true}, // Loading
{false, true, true}, // ModelLoaded
{true, true, true}, // NoModel
};
};
using FCustomizableObjectStatus = FStateMachine<FCustomizableObjectStatusTypes>;
USTRUCT()
struct FMutableModelImageProperties
{
GENERATED_USTRUCT_BODY()
FMutableModelImageProperties()
: Filter(TF_Default)
, SRGB(0)
, FlipGreenChannel(0)
, IsPassThrough(0)
, LODBias(0)
, MipGenSettings(TextureMipGenSettings::TMGS_FromTextureGroup)
, LODGroup(TEXTUREGROUP_World)
, AddressX(TA_Clamp)
, AddressY(TA_Clamp)
{}
FMutableModelImageProperties(const FString& InTextureParameterName, TextureFilter InFilter, uint32 InSRGB,
uint32 InFlipGreenChannel, uint32 bInIsPassThrough, int32 InLODBias, TEnumAsByte<TextureMipGenSettings> InMipGenSettings,
TEnumAsByte<enum TextureGroup> InLODGroup, TEnumAsByte<enum TextureAddress> InAddressX, TEnumAsByte<enum TextureAddress> InAddressY)
: TextureParameterName(InTextureParameterName)
, Filter(InFilter)
, SRGB(InSRGB)
, FlipGreenChannel(InFlipGreenChannel)
, IsPassThrough(bInIsPassThrough)
, LODBias(InLODBias)
, MipGenSettings(InMipGenSettings)
, LODGroup(InLODGroup)
, AddressX(InAddressX)
, AddressY(InAddressY)
{}
// Name in the material.
UPROPERTY()
FString TextureParameterName;
UPROPERTY()
TEnumAsByte<enum TextureFilter> Filter;
UPROPERTY()
uint32 SRGB : 1;
UPROPERTY()
uint32 FlipGreenChannel : 1;
UPROPERTY()
uint32 IsPassThrough : 1;
UPROPERTY()
int32 LODBias;
UPROPERTY()
TEnumAsByte<TextureMipGenSettings> MipGenSettings;
UPROPERTY()
TEnumAsByte<enum TextureGroup> LODGroup;
UPROPERTY()
TEnumAsByte<enum TextureAddress> AddressX;
UPROPERTY()
TEnumAsByte<enum TextureAddress> AddressY;
CUSTOMIZABLEOBJECT_API bool operator!=(const FMutableModelImageProperties& rhs) const;
};
USTRUCT()
struct FMutableRefSocket
{
GENERATED_BODY()
UPROPERTY()
FName SocketName;
UPROPERTY()
FName BoneName;
UPROPERTY()
FVector RelativeLocation = FVector::ZeroVector;
UPROPERTY()
FRotator RelativeRotation = FRotator::ZeroRotator;
UPROPERTY()
FVector RelativeScale = FVector::ZeroVector;
UPROPERTY()
bool bForceAlwaysAnimated = false;
// When two sockets have the same name, the one with higher priority will be picked and the other discarded
UPROPERTY()
int32 Priority = -1;
CUSTOMIZABLEOBJECT_API bool operator ==(const FMutableRefSocket& Other) const;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefSocket& Data);
#endif
};
USTRUCT()
struct FMutableRefLODInfo
{
GENERATED_BODY()
UPROPERTY()
float ScreenSize = 0.f;
UPROPERTY()
float LODHysteresis = 0.f;
UPROPERTY()
bool bSupportUniformlyDistributedSampling = false;
UPROPERTY()
bool bAllowCPUAccess = false;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefLODInfo& Data);
#endif
};
USTRUCT()
struct FMutableRefLODRenderData
{
GENERATED_BODY()
UPROPERTY()
bool bIsLODOptional = false;
UPROPERTY()
bool bStreamedDataInlined = false;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefLODRenderData& Data);
#endif
};
USTRUCT()
struct FMutableRefLODData
{
GENERATED_BODY()
UPROPERTY()
FMutableRefLODInfo LODInfo;
UPROPERTY()
FMutableRefLODRenderData RenderData;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefLODData& Data);
#endif
};
USTRUCT()
struct FMutableRefSkeletalMeshSettings
{
GENERATED_BODY()
UPROPERTY()
bool bEnablePerPolyCollision = false;
UPROPERTY()
float DefaultUVChannelDensity = 0.f;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefSkeletalMeshSettings& Data);
#endif
};
USTRUCT()
struct FMutableRefSkeletalMeshData
{
GENERATED_BODY()
// Reference Skeletal Mesh
UPROPERTY()
TObjectPtr<USkeletalMesh> SkeletalMesh;
// Path to load the ReferenceSkeletalMesh
UPROPERTY()
TSoftObjectPtr<USkeletalMesh> SoftSkeletalMesh;
// Optional USkeletalMeshLODSettings
UPROPERTY()
TObjectPtr<USkeletalMeshLODSettings> SkeletalMeshLODSettings;
// LOD info
UPROPERTY()
TArray<FMutableRefLODData> LODData;
// Sockets
UPROPERTY()
TArray<FMutableRefSocket> Sockets;
// Bounding Box
UPROPERTY()
FBoxSphereBounds Bounds = FBoxSphereBounds(ForceInitToZero);
// Settings
UPROPERTY()
FMutableRefSkeletalMeshSettings Settings;
// Skeleton
UPROPERTY()
TObjectPtr<USkeleton> Skeleton;
// PhysicsAsset
UPROPERTY()
TObjectPtr<UPhysicsAsset> PhysicsAsset;
// Post Processing AnimBP
UPROPERTY()
TSoftClassPtr<UAnimInstance> PostProcessAnimInst;
// Shadow PhysicsAsset
UPROPERTY()
TObjectPtr<UPhysicsAsset> ShadowPhysicsAsset;
// Asset user data
UPROPERTY()
TArray<int32> AssetUserDataIndices;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableRefSkeletalMeshData& Data);
#endif
};
USTRUCT()
struct FAnimBpOverridePhysicsAssetsInfo
{
GENERATED_BODY()
UPROPERTY()
TSoftClassPtr<UAnimInstance> AnimInstanceClass;
UPROPERTY()
TSoftObjectPtr<UPhysicsAsset> SourceAsset;
UPROPERTY()
int32 PropertyIndex = -1;
CUSTOMIZABLEOBJECT_API bool operator==(const FAnimBpOverridePhysicsAssetsInfo& Rhs) const;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FAnimBpOverridePhysicsAssetsInfo& Info);
#endif
};
USTRUCT()
struct FMutableSkinWeightProfileInfo
{
GENERATED_USTRUCT_BODY()
FMutableSkinWeightProfileInfo() {};
FMutableSkinWeightProfileInfo(FName InName, uint32 InNameId, bool InDefaultProfile, int8 InDefaultProfileFromLODIndex) : Name(InName),
NameId(InNameId), DefaultProfile(InDefaultProfile), DefaultProfileFromLODIndex(InDefaultProfileFromLODIndex) {};
UPROPERTY()
FName Name;
UPROPERTY()
uint32 NameId = 0;
UPROPERTY()
bool DefaultProfile = false;
UPROPERTY(meta = (ClampMin = 0))
int8 DefaultProfileFromLODIndex = 0;
CUSTOMIZABLEOBJECT_API bool operator==(const FMutableSkinWeightProfileInfo& Other) const;
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FMutableSkinWeightProfileInfo& Info);
#endif
};
// TODO: Optimize this struct
USTRUCT()
struct FMutableStreamableBlock
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
uint32 FileId = 0;
/** Used to store properties of the data, necessary for its recovery. For instance if it is high-res. */
UPROPERTY()
uint16 Flags = 0;
uint16 IsPrefetched = 0;
UPROPERTY()
uint64 Offset = 0;
friend FArchive& operator<<(FArchive& Ar, FMutableStreamableBlock& Data)
{
Ar << Data.FileId;
Ar << Data.Flags;
Ar << Data.Offset;
return Ar;
}
};
static_assert(sizeof(FMutableStreamableBlock) == 8 * 2);
USTRUCT()
struct FRealTimeMorphStreamable
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TArray<FName> NameResolutionMap;
UPROPERTY()
FMutableStreamableBlock Block;
UPROPERTY()
uint32 Size = 0;
UPROPERTY()
uint32 SourceId = 0;
friend FArchive& operator<<(FArchive& Ar, FRealTimeMorphStreamable& Elem)
{
Ar << Elem.NameResolutionMap;
Ar << Elem.Size;
Ar << Elem.Block;
Ar << Elem.SourceId;
return Ar;
}
};
USTRUCT()
struct FMutableMeshMetadata
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
uint32 MorphMetadataId = 0;
UPROPERTY()
uint32 ClothingMetadataId = 0;
UPROPERTY()
uint32 SurfaceMetadataId = 0;
friend FArchive& operator<<(FArchive& Ar, FMutableMeshMetadata& Elem)
{
Ar << Elem.MorphMetadataId;
Ar << Elem.ClothingMetadataId;
Ar << Elem.SurfaceMetadataId;
return Ar;
}
};
USTRUCT()
struct FMutableSurfaceMetadata
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
FName MaterialSlotName = FName{};
UPROPERTY()
bool bCastShadow = true;
friend FArchive& operator<<(FArchive& Ar, FMutableSurfaceMetadata& Elem)
{
Ar << Elem.MaterialSlotName;
Ar << Elem.bCastShadow;
return Ar;
}
};
USTRUCT()
struct FClothingStreamable
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 ClothingAssetIndex = INDEX_NONE;
UPROPERTY()
int32 ClothingAssetLOD = INDEX_NONE;
UPROPERTY()
int32 PhysicsAssetIndex = INDEX_NONE;
UPROPERTY()
uint32 Size = 0;
UPROPERTY()
FMutableStreamableBlock Block;
UPROPERTY()
uint32 SourceId = 0;
friend FArchive& operator<<(FArchive& Ar, FClothingStreamable& Elem)
{
Ar << Elem.ClothingAssetIndex;
Ar << Elem.ClothingAssetLOD;
Ar << Elem.PhysicsAssetIndex;
Ar << Elem.Size;
Ar << Elem.Block;
Ar << Elem.SourceId;
return Ar;
}
};
USTRUCT()
struct FMorphTargetVertexData
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
FVector3f PositionDelta = FVector3f::ZeroVector;
UPROPERTY()
FVector3f TangentZDelta = FVector3f::ZeroVector;
UPROPERTY()
uint32 MorphNameIndex = 0;
friend FArchive& operator<<(FArchive& Ar, FMorphTargetVertexData& Data)
{
Ar << Data.PositionDelta;
Ar << Data.TangentZDelta;
Ar << Data.MorphNameIndex;
return Ar;
}
};
static_assert(sizeof(FMorphTargetVertexData) == sizeof(FVector3f)*2 + sizeof(uint32)); // Make sure no padding is present.
template<> struct TCanBulkSerialize<FMorphTargetVertexData> { enum { Value = true }; };
struct FMutableParameterIndex
{
FMutableParameterIndex(int32 InIndex, int32 InTypedIndex)
{
Index = InIndex;
TypedIndex = InTypedIndex;
}
int32 Index = INDEX_NONE;
int32 TypedIndex = INDEX_NONE;
};
USTRUCT()
struct FIntegerParameterOptionKey
{
GENERATED_BODY()
UPROPERTY()
FString ParameterName;
UPROPERTY()
FString ParameterOption;
#if WITH_EDITOR
friend CUSTOMIZABLEOBJECT_API uint32 GetTypeHash(const FIntegerParameterOptionKey& Key);
bool operator==(const FIntegerParameterOptionKey& Other) const = default;
#endif
};
USTRUCT()
struct FIntegerParameterOptionDataTable
{
GENERATED_BODY()
UPROPERTY()
TSet<TSoftObjectPtr<UDataTable>> DataTables;
};
USTRUCT()
struct FIntegerParameterUIData
{
GENERATED_BODY()
FIntegerParameterUIData() = default;
CUSTOMIZABLEOBJECT_API FIntegerParameterUIData(const FMutableParamUIMetadata& InParamUIMetadata);
UPROPERTY()
FMutableParamUIMetadata ParamUIMetadata;
friend FArchive& operator<<(FArchive& Ar, FIntegerParameterUIData& Struct);
};
USTRUCT()
struct FMutableParameterData
{
GENERATED_BODY()
FMutableParameterData() = default;
CUSTOMIZABLEOBJECT_API FMutableParameterData(const FMutableParamUIMetadata& InParamUIMetadata, EMutableParameterType InType);
UPROPERTY()
FMutableParamUIMetadata ParamUIMetadata;
/** Parameter type */
UPROPERTY()
EMutableParameterType Type = EMutableParameterType::None;
/** In the case of an integer parameter, store here all options */
UPROPERTY()
TMap<FString, FIntegerParameterUIData> ArrayIntegerParameterOption;
/** How are the different options selected (one, one or none, etc...) */
UPROPERTY()
ECustomizableObjectGroupType IntegerParameterGroupType = ECustomizableObjectGroupType::COGT_ONE_OR_NONE;
friend FArchive& operator<<(FArchive& Ar, FMutableParameterData& Struct);
};
USTRUCT()
struct FMutableStateData
{
GENERATED_BODY()
UPROPERTY()
FMutableStateUIMetadata StateUIMetadata;
/** In this mode instances and their temp data will be reused between updates. It will be much faster but spend as much as ten times the memory.
* Useful for customization lockers with few characters that are going to have their parameters changed many times, not for in-game */
UPROPERTY()
bool bLiveUpdateMode = false;
/** If this is enabled, texture streaming won't be used for this state, and full images will be generated when an instance is first updated. */
UPROPERTY()
bool bDisableTextureStreaming = false;
UPROPERTY()
bool bReuseInstanceTextures = false;
UPROPERTY()
TMap<FString, FString> ForcedParameterValues;
friend FArchive& operator<<(FArchive& Ar, FMutableStateData& Struct);
};
/** This is encoded in exact bits so if extended, review its uses everywhere. */
enum class EMutableFileFlags : uint8
{
None = 0,
HighRes = 1 << 0
};
namespace MutablePrivate
{
enum class EStreamableDataType : uint32 // uint32 for padding and DDC purposes
{
None = 0,
Model,
RealTimeMorph,
Clothing,
DataTypeCount
};
#if WITH_EDITOR
struct FBlock
{
/** Used on some data types as the index to the block stored in the CustomizableObject */
uint32 Id;
/** Used on some data types to group blocks. */
uint32 SourceId;
/** Size of the data block. */
uint32 Size;
uint32 Padding = 0;
/** Offset in the full source streamed data file that is created when compiling. */
uint64 Offset;
friend FArchive& operator<<(FArchive& Ar, FBlock& Data)
{
Ar << Data.Id;
Ar << Data.SourceId;
Ar << Data.Size;
Ar << Data.Offset;
return Ar;
};
};
//template<> struct TCanBulkSerialize<FBlock> { enum { Value = true }; };
struct FFile
{
EStreamableDataType DataType = EStreamableDataType::None;
/** Rom ResourceType. */
uint16 ResourceType = 0;
/** Common flags of the data stored in this file. See EMutableFileFlags.*/
uint16 Flags = 0;
/** Id generated from a hash of the file content + offset to avoid collisions. */
uint32 Id = 0;
uint32 Padding = 0;
/** List of blocks that are contained in the file, in order. */
TArray<FBlock> Blocks;
/** Get the total size of blocks in this file. */
CUSTOMIZABLEOBJECT_API uint64 GetSize() const;
/** Copy the requested block to the requested buffer and return its size. */
CUSTOMIZABLEOBJECT_API void GetFileData(struct FMutableCachedPlatformData*, TArray64<uint8>& DataDestination, bool bDropData);
friend FArchive& operator<<(FArchive& Ar, FFile& Data)
{
Ar << Data.DataType;
Ar << Data.ResourceType;
Ar << Data.Flags;
Ar << Data.Id;
Ar << Data.Blocks;
return Ar;
};
};
struct FFileCategoryID
{
FFileCategoryID(EStreamableDataType DataType, uint16 ResourceType, uint16 Flags);
FFileCategoryID() = default;
// EDataType
EStreamableDataType DataType = EStreamableDataType::None;
/** Rom ResourceType. */
uint16 ResourceType = 0;
/** Rom flags */
uint16 Flags = 0;
friend uint32 GetTypeHash(const FFileCategoryID& Key);
bool operator==(const FFileCategoryID& Other) const = default;
};
struct FFileCategory
{
FFileCategoryID Id;
// Accumulated size of resources from this category
uint64 DataSize = 0;
// Categories within a bucket with a limited number of files will use sequential ID starting at FirstFile
// and up to FirstFile + NumFiles.
uint32 FirstFile = 0;
uint32 NumFiles = 0;
};
/** Group bulk data by categories. */
struct FFileBucket
{
// Resources belonging to these categories will be added to the bucket.
TArray<FFileCategory> Categories;
// Accumulated size of the resources of all categories within this bucket
uint64 DataSize = 0;
};
struct FModelStreamableData
{
void Get(uint32 Key, TArrayView64<uint8> Destination, bool bDropData)
{
TArray64<uint8>* Buffer = Data.Find(Key);
check(Buffer);
check(Destination.Num() == Buffer->Num());
FMemory::Memcpy(Destination.GetData(), Buffer->GetData(), Buffer->Num());
if (bDropData)
{
Buffer->Empty();
}
}
void Set(uint32 Key, const uint8* Source, int64 Size)
{
check(Source);
check(Size);
TArray64<uint8>& Buffer = Data.Add(Key);
check(Buffer.Num() == 0);
Buffer.SetNumUninitialized(Size);
FMemory::Memcpy(Buffer.GetData(), Source, Size);
}
// Temp, to be replaced with disk storage
TMap<uint32, TArray64<uint8> > Data;
};
struct FMutableCachedPlatformData
{
/** mu::Model */
TSharedPtr<mu::FModel, ESPMode::ThreadSafe> Model;
/** UModelResources */
TStrongObjectPtr<UModelResources> ModelResources;
/** Streamable resources info such as files and offsets. */
TSharedPtr<FModelStreamableBulkData> ModelStreamableBulkData;
/** Struct containing map of RomId to RomBytes. */
FModelStreamableData ModelStreamableData;
/** */
FModelStreamableData MorphStreamableData;
/** */
FModelStreamableData ClothingStreamableData;
/** List of files to serialize. Each file has a list of binary blocks to be serialized. */
TArray<FFile> BulkDataFiles;
};
/** Generate the list of BulkData files with a restriction to the number of files to generate per bucket.
* Resources will be split into two buckets for non-optional and optional BulkData.
*/
void CUSTOMIZABLEOBJECT_API GenerateBulkDataFilesListWithFileLimit(
TSharedPtr<const mu::FModel, ESPMode::ThreadSafe> Model,
FModelStreamableBulkData& ModelStreamableBulkData,
uint32 NumFilesPerBucket,
TArray<FFile>& OutBulkDataFiles);
/** Generate the list of BulkData files with a soft restriction to the size of the files.
*/
void CUSTOMIZABLEOBJECT_API GenerateBulkDataFilesListWithSizeLimit(
TSharedPtr<const mu::FModel, ESPMode::ThreadSafe> Model,
FModelStreamableBulkData& ModelStreamableBulkData,
const ITargetPlatform* TargetPlatform,
uint64 TargetBulkDataFileBytes,
TArray<FFile>& OutBulkDataFiles);
/** Compute the number of files and sizes the BulkData will be split into and update
* the streamable's FileIds and Offsets.
*/
void GenerateBulkDataFilesList(
TSharedPtr<const mu::FModel, ESPMode::ThreadSafe> Model,
FModelStreamableBulkData& StreamableBulkData,
bool bUseRomTypeAndFlagsToFilter,
TFunctionRef<void(const FFileCategoryID&, const FClassifyNode&, TArray<FFile>&)> CreateFileList,
TArray<FFile>& OutBulkDataFiles);
void CUSTOMIZABLEOBJECT_API SerializeBulkDataFiles(
FMutableCachedPlatformData& CachedPlatformData,
TArray<FFile>& BulkDataFiles,
TFunctionRef<void(FFile&, TArray64<uint8>&, uint32 FileIndex)> WriteFile,
bool bDropData);
UE::DerivedData::FValueId CUSTOMIZABLEOBJECT_API GetDerivedDataModelId();
UE::DerivedData::FValueId CUSTOMIZABLEOBJECT_API GetDerivedDataModelResourcesId();
UE::DerivedData::FValueId CUSTOMIZABLEOBJECT_API GetDerivedDataModelStreamableBulkDataId();
UE::DerivedData::FValueId CUSTOMIZABLEOBJECT_API GetDerivedDataBulkDataFilesId();
#endif
}
struct FModelStreamableBulkData
{
/** Map of Hash to Streaming blocks, used to stream a block of data representing a resource from the BulkData */
TMap<uint32, FMutableStreamableBlock> ModelStreamables;
TMap<uint32, FClothingStreamable> ClothingStreamables;
TMap<uint32, FRealTimeMorphStreamable> RealTimeMorphStreamables;
TArray<FByteBulkData> StreamableBulkData;
#if WITH_EDITORONLY_DATA
// Used to know if roms and other resources must be streamed from the DDC.
bool bIsStoredInDDC = false;
UE::DerivedData::FCacheKey DDCKey = UE::DerivedData::FCacheKey::Empty;
UE::DerivedData::ECachePolicy DDCDefaultPolicy = UE::DerivedData::ECachePolicy::Default;
#endif
// File path to stream resources from when not using FByteBulkData or DDC.
FString FullFilePath;
CUSTOMIZABLEOBJECT_API void Serialize(FArchive& Ar, UObject* Owner, bool bCooked);
#if WITH_EDITORONLY_DATA
friend FArchive& operator<<(FArchive& Ar, FModelStreamableBulkData& Data)
{
Ar << Data.ModelStreamables;
Ar << Data.ClothingStreamables;
Ar << Data.RealTimeMorphStreamables;
// Don't serialize FByteBulkData manually, the data will be skipped.
Ar << Data.FullFilePath;
return Ar;
}
#endif
};
/** Interface class to allow custom serialization of FModelStreamableBulkData and its FBulkData. */
UCLASS()
class UModelStreamableData : public UObject
{
GENERATED_BODY()
UModelStreamableData();
public:
virtual void Serialize(FArchive& Ar) override;
virtual void PostLoad() override;
TSharedPtr<FModelStreamableBulkData> StreamingData;
};
USTRUCT()
struct FMutableParamNameSet
{
GENERATED_BODY()
TSet<FString> ParamNames;
};
/** Class containing all UE resources derived from a CO compilation. These resources will be embedded in the CO at cook time but not in the editor.
* Editor compilations will serialize this class to disk using the Serialize methods. Ensure new fields are serialized, too.
* Variables and settings that should not change until the CO is re-compiled should be stored here. */
UCLASS(MinimalAPI)
class UModelResources : public UObject
{
GENERATED_BODY()
public:
/**
* All the SkeletalMeshes generated for this CustomizableObject instances will use the Reference Skeletal Mesh
* properties for everything that Mutable doesn't create or modify. This struct stores the information used from
* the Reference Skeletal Meshes to avoid having them loaded at all times. This includes data like LOD distances,
* LOD render data settings, Mesh sockets, Bounding volumes, etc.
*
* Index with CustomizableObject Component index
*/
UPROPERTY()
TArray<FMutableRefSkeletalMeshData> ReferenceSkeletalMeshesData;
/** Skeletons used by the compiled mu::FModel. */
UPROPERTY()
TArray<TSoftObjectPtr<USkeleton>> Skeletons;
/** Materials used by the compiled mu::FModel */
UPROPERTY()
TArray<TSoftObjectPtr<UMaterialInterface>> Materials;
/** PassThrough textures used by the mu::FModel. */
UPROPERTY()
TArray<TSoftObjectPtr<UTexture>> PassThroughTextures;
/** PassThrough meshes used by the mu::FModel. */
UPROPERTY()
TArray<TSoftObjectPtr<UStreamableRenderAsset>> PassThroughMeshes;
#if WITH_EDITORONLY_DATA
/** Runtime referenced textures used by the mu::FModel. */
UPROPERTY()
TArray<TSoftObjectPtr<UTexture2D>> RuntimeReferencedTextures;
/** Runtime referenced meshes used by the mu::FModel.
* TODO: Move to FMutableSourceMeshData when runtime is really implemented.
*/
UPROPERTY()
TArray<TSoftObjectPtr<const UStreamableRenderAsset>> RuntimeReferencedMeshes;
#endif
/** Physics assets gathered from the SkeletalMeshes, to be used in mesh generation in-game */
UPROPERTY()
TArray<TSoftObjectPtr<UPhysicsAsset>> PhysicsAssets;
/** UAnimBlueprint assets gathered from the SkeletalMesh, to be used in mesh generation in-game */
UPROPERTY()
TArray<TSoftClassPtr<UAnimInstance>> AnimBPs;
/** */
UPROPERTY()
TArray<FAnimBpOverridePhysicsAssetsInfo> AnimBpOverridePhysiscAssetsInfo;
/** Material slot names for the materials referenced by the surfaces. */
UPROPERTY()
TArray<FName> MaterialSlotNames;
UPROPERTY()
TMap<FString, uint32> BoneNamesMap;
/** Mesh sockets provided by the part skeletal meshes, to be merged in the generated meshes */
UPROPERTY()
TArray<FMutableRefSocket> SocketArray;
UPROPERTY()
TArray<FMutableSkinWeightProfileInfo> SkinWeightProfilesInfo;
UPROPERTY()
TArray<FMutableModelImageProperties> ImageProperties;
UPROPERTY()
TMap<uint32, FMutableMeshMetadata> MeshMetadata;
UPROPERTY()
TMap<uint32, FMutableSurfaceMetadata> SurfaceMetadata;
/** Parameter UI metadata information for all the dependencies of this Customizable Object. */
UPROPERTY()
TMap<FString, FMutableParameterData> ParameterUIDataMap;
/** State UI metadata information for all the dependencies of this Customizable Object */
UPROPERTY()
TMap<FString, FMutableStateData> StateUIDataMap;
#if WITH_EDITORONLY_DATA
/** DataTable used by an int parameter and its value. */
UPROPERTY()
TMap<FIntegerParameterOptionKey, FIntegerParameterOptionDataTable> IntParameterOptionDataTable;
#endif
UPROPERTY()
TArray<FCustomizableObjectClothConfigData> ClothSharedConfigsData;
UPROPERTY()
TArray<FCustomizableObjectClothingAssetData> ClothingAssetsData;
/** Currently not used, this option should be selectable from editor maybe as a compilation flag */
UPROPERTY()
bool bAllowClothingPhysicsEditsPropagation = true;
#if WITH_EDITORONLY_DATA
// Stores what param names use a certain table as a table can be used from multiple table nodes, useful for partial compilations to restrict params
UPROPERTY()
TMap<FString, FMutableParamNameSet> TableToParamNames;
/** Map to identify what CustomizableObject owns a parameter. Used to display a tooltip when hovering a parameter
* in the Prev. instance panel */
UPROPERTY()
TMap<FString, FString> CustomizableObjectPathMap;
UPROPERTY()
TMap<FString, FCustomizableObjectIdPair> GroupNodeMap;
/** If the object is compiled with maximum optimizations. */
UPROPERTY()
bool bIsCompiledWithOptimization = true;
/** This is a non-user-controlled flag to disable streaming (set at object compilation time, depending on optimization). */
UPROPERTY()
bool bIsTextureStreamingDisabled = false;
/** List of external packages that if changed, a compilation is required.
* Key is the package name. Value is the the UPackage::Guid, which is regenerated each time the packages is saved.
*
* Updated each time the CO is compiled and saved in the Derived Data. */
UPROPERTY()
TMap<FName, FGuid> ParticipatingObjects;
UPROPERTY()
TArray<FCustomizableObjectResourceData> StreamedResourceDataEditor;
UPROPERTY()
TArray<FCustomizableObjectResourceData> StreamedExtensionDataEditor;
#endif
// Constant Resources streamed in on demand when generating meshes
UPROPERTY()
TArray<FCustomizableObjectStreamedResourceData> StreamedResourceData;
// mu::FExtensionData::Index is an index into this array when mu::ExtensionData::Origin is ConstantAlwaysLoaded
UPROPERTY()
TArray<FCustomizableObjectResourceData> AlwaysLoadedExtensionData;
// mu::FExtensionData::Index is an index into this array when mu::ExtensionData::Origin is ConstantStreamed
UPROPERTY()
TArray<FCustomizableObjectStreamedResourceData> StreamedExtensionData;
/** Max number of LODs in the compiled Model. */
UPROPERTY()
TMap<FName, uint8> NumLODsAvailable;
/** Max number of LODs to stream. Mutable will always generate at least one LOD. */
UPROPERTY()
TMap<FName, uint8> NumLODsToStream;
/** First LOD available, some platforms may remove lower LODs when cooking, this MinLOD represents the first LOD we can generate */
UPROPERTY()
TMap<FName, uint8> FirstLODAvailable;
/** Name of all possible components. Index is the ObjectComponentIndex. */
UPROPERTY()
TArray<FName> ComponentNamesPerObjectComponent;
/** Minimum LOD to render per Platform. */
UPROPERTY()
TMap<FName, FPerPlatformInt> MinLODPerComponent;
/** Minimum LOD to render per Quality level. */
UPROPERTY()
TMap<FName, FPerQualityLevelInt> MinQualityLevelLODPerComponent;
UPROPERTY()
TMap<FName, TObjectPtr<UTexture>> TextureParameterDefaultValues;
UPROPERTY()
TMap<FName, TObjectPtr<USkeletalMesh>> SkeletalMeshParameterDefaultValues;
UPROPERTY()
FString ReleaseVersion;
UPROPERTY()
int32 CodeVersion = 0;
#if WITH_EDITORONLY_DATA
/** Value of the variable TextureCompression in the last compilation of this CO.
* this is needed since we can compile a CO through blueprints with a different
* compilation setting than the stored in the COE.*/
UPROPERTY()
bool bCompiledWithHDTextureCompression = false;
CUSTOMIZABLEOBJECT_API void InitCookData(UObject& InCustomizableObject);
#endif
};
UCLASS(MinimalAPI, config = Engine)
class UCustomizableObjectBulk : public UObject
{
public:
GENERATED_BODY()
//~ Begin UObject Interface
CUSTOMIZABLEOBJECT_API virtual void PostLoad() override;
//~ End UObject Interface
/** */
const FString& GetBulkFilePrefix() const { return BulkFilePrefix; }
CUSTOMIZABLEOBJECT_API TUniquePtr<IAsyncReadFileHandle> OpenFileAsyncRead(uint32 FileId, uint32 Flags) const;
#if WITH_EDITOR
//~ Begin UObject Interface
CUSTOMIZABLEOBJECT_API virtual void CookAdditionalFilesOverride(const TCHAR*, const ITargetPlatform*, TFunctionRef<void(const TCHAR*, void*, int64)>) override;
//~ End UObject Interface
#endif
#if WITH_EDITOR
private:
#endif
/** Prefix to locate bulkfiles for loading, using the file ids in each FMutableStreamableBlock. */
FString BulkFilePrefix;
};
USTRUCT()
struct FMutableMeshComponentData
{
GENERATED_USTRUCT_BODY()
/** Name to identify this component. */
UPROPERTY(EditAnywhere, Category = CustomizableObject)
FName Name;
/** All the SkeletalMeshes generated for this CustomizableObject instances will use the Reference Skeletal Mesh
* properties for everything that Mutable doesn't create or modify. This includes data like LOD distances, Physics
* properties, Bounding Volumes, Skeleton, etc.
*
* While a CustomizableObject instance is being created for the first time, and in some situation with lots of
* objects this may require some seconds, the Reference Skeletal Mesh is used for the actor. This works as a better
* solution than the alternative of not showing anything, although this can be disabled with the function
* "SetReplaceDiscardedWithReferenceMeshEnabled" (See the c++ section). */
UPROPERTY(EditAnywhere, Category = CustomizableObject)
TObjectPtr<USkeletalMesh> ReferenceSkeletalMesh;
};
/** Strongly typed index for the index of a component in a UCustomizableObject. */
USTRUCT()
struct FCustomizableObjectComponentIndex
{
GENERATED_BODY()
private:
int32 Index = 0;
public:
explicit inline FCustomizableObjectComponentIndex(int32 InIndex=0)
: Index(InIndex)
{
}
inline void Invalidate()
{
Index = INDEX_NONE;
}
inline bool IsValid() const
{
return Index != INDEX_NONE;
}
inline int32 GetValue() const
{
return Index;
}
inline bool operator==(const FCustomizableObjectComponentIndex&) const = default;
};
#if WITH_EDITORONLY_DATA
// This is a manual version number for the binary blobs in this asset.
// Increasing it invalidates all the previously compiled models.
UENUM()
enum class ECustomizableObjectVersions : int32
{
FirstEnumeratedVersion = 450,
DeterminisiticMeshVertexIds,
NumRuntimeReferencedTextures,
DeterminisiticLayoutBlockIds,
BackoutDeterminisiticLayoutBlockIds,
FixWrappingProjectorLayoutBlockId,
MeshReferenceSupport,
ImproveMemoryUsageForStreamableBlocks,
FixClipMeshWithMeshCrash,
SkeletalMeshLODSettingsSupport,
RemoveCustomCurve,
AddEditorGamePlayTags,
AddedParameterThumbnailsToEditor,
ComponentsLODsRedesign,
ComponentsLODsRedesign2,
LayoutToPOD,
AddedRomFlags,
LayoutNodeCleanup,
AddSurfaceAndMeshMetadata,
TablesPropertyNameBug,
DataTablesParamTrackingForCompileOnlySelected,
CompilationOptimizationsMeshFormat,
ModelStreamableBulkData,
LayoutBlocksAsInt32,
IntParameterOptionDataTable,
RemoveLODCountLimit,
IntParameterOptionDataTablePartialBackout,
IntParameterOptionDataTablePartialRestore,
CorrectlySerializeTableToParamNames,
AddMaterialSlotNameIndexToSurfaceMetadata,
NodeComponentMesh,
MoveEditNodesToModifiers,
DerivedDataCache,
ComponentsArray,
FixComponentNames,
AddedFaceCullStrategyToSomeOperations,
DDCParticipatingObjects,
GroupRomsBySource,
RemovedGroupRomsBySource,
ReGroupRomsBySource,
UIMetadataGameplayTags,
TransformInMeshModifier,
SurfaceMetadataSlotNameIndexToName,
BulkDataFilesNumFilesLimit,
RemoveModifiersHack,
SurfaceMetadataSerialized,
FixesForMeshSectionMultipleOutputs,
ImageParametersInServerBuilds,
RemovedUnnecessarySerializationVersioning,
AddTextureCompressionSettingCompilationInfo,
RestructureConstantImageData,
RestructureConstantMeshData,
RestructureRomData,
RestructureRomDataRemovingRomHash,
ModifiedRomCompiledDataSerialization,
ModelResourcesExtensionData,
LODsPerComponent,
LODsPerComponentTypeMismatch,
ImageHiResLODsUseLODGroupInfo,
MovedTableRowNoneGenerationToUnreal,
RemoveObsoletMeshInterpolateAndGeometryOp,
RemoveObsoleteDataTypesFromEnum,
ConvertModelResourcesToUObject,
RemoveObsoletImageGradientOp,
MeshReferencesExtendedForCompilation,
RemoveObsoleteBoolOps,
AddOverlayMaterials,
PrefetchHighQualityMipMaps,
AddedMeshParameterOp,
AddedMeshParameterOpForDDCPollution,
ExtendedMeshParameterArgumentsWithLODAndSection,
AddAssetUserDataEditor,
MeshDataRomSplit,
MeshDataRomSplitBackout,
MovedLODSettingsToMeshComponentNode,
AddedMeshPrepareLayoutOp,
AddedMeshIDToMeshParamOp,
ClothMorphMeshMetadata,
AddedMeshIDToMeshParamOpBackout,
MeshDataRomSplitSerializationFix,
ReaddAddedMeshIDToMeshParamOp,
AddConnectedChildObjectComponentsToPrepass,
FixMeshReusalDueToLayouts,
IncorrectBonePoseMerging,
CoreParameterUObjects,
MoveMeshMetadataToOperation,
MovePhysicsBodiesToRoms,
// -----<new versions can be added above this line>--------
LastCustomizableObjectVersion
};
#endif
UCLASS(MinimalAPI)
class UCustomizableObjectPrivate : public UObject
{
GENERATED_BODY()
TSharedPtr<mu::FModel, ESPMode::ThreadSafe> MutableModel;
/** Stores streamable data info to be used by MutableModel In-Game. Cooked resources. */
UPROPERTY()
TObjectPtr<UModelStreamableData> ModelStreamableData;
/** Stores resources to be used by MutableModel In-Game. Cooked resources. */
UPROPERTY()
TObjectPtr<UModelResources> ModelResources;
#if WITH_EDITORONLY_DATA
/**
* Stores resources to be used by MutableModel in the Editor. Editor resources.
* Editor-Only to avoid packaging assets referenced by editor compilations.
*/
UPROPERTY(Transient)
TObjectPtr<UModelResources> ModelResourcesEditor;
/**
* Stores streamable data info to be used by MutableModel in the Editor. Editor streaming.
*/
TSharedPtr<FModelStreamableBulkData> ModelStreamableDataEditor;
#endif
public:
/** Must be called after unlocking the CustomizableObject. */
CUSTOMIZABLEOBJECT_API void SetModel(const TSharedPtr<mu::FModel, ESPMode::ThreadSafe>& Model, const FGuid Identifier);
CUSTOMIZABLEOBJECT_API const TSharedPtr<mu::FModel, ESPMode::ThreadSafe>& GetModel();
CUSTOMIZABLEOBJECT_API const TSharedPtr<const mu::FModel, ESPMode::ThreadSafe> GetModel() const;
CUSTOMIZABLEOBJECT_API UModelResources* GetModelResources();
CUSTOMIZABLEOBJECT_API const UModelResources* GetModelResources() const;
CUSTOMIZABLEOBJECT_API const UModelResources& GetModelResourcesChecked() const;
#if WITH_EDITORONLY_DATA
CUSTOMIZABLEOBJECT_API UModelResources* GetModelResources(bool bIsCooking);
CUSTOMIZABLEOBJECT_API const UModelResources* GetModelResources(bool bIsCooking) const;
CUSTOMIZABLEOBJECT_API void SetModelResources(UModelResources* InModelResources, bool bIsCooking);
CUSTOMIZABLEOBJECT_API void SetModelStreamableBulkData(const TSharedPtr<FModelStreamableBulkData>& StreamableData, bool bIsCooking);
#endif
CUSTOMIZABLEOBJECT_API TSharedPtr<FModelStreamableBulkData> GetModelStreamableBulkData(bool bIsCooking = false) const;
// See UCustomizableObjectSystem::LockObject()
CUSTOMIZABLEOBJECT_API bool IsLocked() const;
/** Modify the provided mutable parameters so that the forced values for the given customizable object state are applied. */
CUSTOMIZABLEOBJECT_API void ApplyStateForcedValuesToParameters(FCustomizableObjectInstanceDescriptor& Descriptor);
CUSTOMIZABLEOBJECT_API int32 FindParameter(const FString& Name) const;
CUSTOMIZABLEOBJECT_API int32 FindParameterTyped(const FString& Name, EMutableParameterType Type) const;
CUSTOMIZABLEOBJECT_API EMutableParameterType GetParameterType(int32 ParamIndex) const;
CUSTOMIZABLEOBJECT_API int32 FindIntParameterValue(int32 ParamIndex, const FString& Value) const;
CUSTOMIZABLEOBJECT_API FString GetStateName(int32 StateIndex) const;
#if WITH_EDITORONLY_DATA
CUSTOMIZABLEOBJECT_API void PostCompile();
#endif
/** Returns a pointer to the BulkData subobject, only valid in packaged builds. */
CUSTOMIZABLEOBJECT_API const UCustomizableObjectBulk* GetStreamableBulkData() const;
CUSTOMIZABLEOBJECT_API UCustomizableObject* GetPublic() const;
#if WITH_EDITOR
/** Compose file name. */
CUSTOMIZABLEOBJECT_API FString GetCompiledDataFileName(const ITargetPlatform* InTargetPlatform = nullptr, bool bIsDiskStreamer = false) const;
/** DDC helpers. BuildDerivedDataKey is expensive, try to cache it as much as possible. */
CUSTOMIZABLEOBJECT_API TArray<uint8> BuildDerivedDataKey(FCompilationOptions Options);
CUSTOMIZABLEOBJECT_API UE::DerivedData::FCacheKey GetDerivedDataCacheKeyForOptions(FCompilationOptions InOptions);
/** Log data for debugging purposes */
CUSTOMIZABLEOBJECT_API void LogMemory();
#endif
/** Rebuild ParameterProperties from the current compiled model. */
CUSTOMIZABLEOBJECT_API void UpdateParameterPropertiesFromModel(const TSharedPtr<mu::FModel>& Model);
CUSTOMIZABLEOBJECT_API void AddUncompiledCOWarning(const FString& AdditionalLoggingInfo);
#if WITH_EDITOR
// Create new GUID for this CO
CUSTOMIZABLEOBJECT_API void UpdateVersionId();
CUSTOMIZABLEOBJECT_API FGuid GetVersionId() const;
CUSTOMIZABLEOBJECT_API void SaveEmbeddedData(FArchive& Ar);
// Add a profile that stores the values of the parameters used by the CustomInstance.
CUSTOMIZABLEOBJECT_API FReply AddNewParameterProfile(FString Name, class UCustomizableObjectInstance& CustomInstance);
/** Generic Load methods to read compiled data */
CUSTOMIZABLEOBJECT_API bool LoadModelResources(FArchive& Ar, const ITargetPlatform* InTargetPlatform, bool bSkipEditorOnlyData = false);
CUSTOMIZABLEOBJECT_API void LoadModelStreamableBulk(FArchive& Ar, bool bIsCooking);
CUSTOMIZABLEOBJECT_API void LoadModel(FArchive& Ar);
/** Load compiled data for the running platform from disk, this is used to load Editor Compilations. */
CUSTOMIZABLEOBJECT_API void LoadCompiledDataFromDisk();
/** Loads data previously compiled in BeginCacheForCookedPlatformData onto the UProperties in *this,
* in preparation for saving the cooked package for *this or for a CustomizableObjectInstance using *this.
* Returns whether the data was successfully loaded. */
CUSTOMIZABLEOBJECT_API bool TryLoadCompiledCookDataForPlatform(const ITargetPlatform* TargetPlatform);
#endif
// Data that may be stored in the asset itself, only in packaged builds.
CUSTOMIZABLEOBJECT_API void LoadEmbeddedData(FArchive& Ar);
/** Compute bIsChildObject if currently possible to do so. Return whether it was computed. */
CUSTOMIZABLEOBJECT_API bool TryUpdateIsChildObject();
CUSTOMIZABLEOBJECT_API void SetIsChildObject(bool bIsChildObject);
/** Return the names used by mutable to identify which mu::FImage should be considered of LowPriority. */
CUSTOMIZABLEOBJECT_API void GetLowPriorityTextureNames(TArray<FString>& OutTextureNames);
/** Return the MinLOD index to generate based on the active LODSettings (PerPlatformMinLOD or PerQualityLevelMinLOD) */
CUSTOMIZABLEOBJECT_API uint8 GetMinLODIndex(const FName& ComponentName) const;
#if WITH_EDITOR
/** See ICustomizableObjectEditorModule::IsCompilationOutOfDate. */
CUSTOMIZABLEOBJECT_API bool IsCompilationOutOfDate(bool bSkipIndirectReferences, TArray<FName>& OutOfDatePackages, TArray<FName>& AddedPackages, TArray<FName>& RemovedPackages, bool& bReleaseVersionDiff) const;
#endif
CUSTOMIZABLEOBJECT_API TArray<FString>& GetCustomizableObjectClassTags();
CUSTOMIZABLEOBJECT_API TArray<FString>& GetPopulationClassTags();
CUSTOMIZABLEOBJECT_API TMap<FString, FParameterTags>& GetCustomizableObjectParametersTags();
#if WITH_EDITORONLY_DATA
CUSTOMIZABLEOBJECT_API TArray<FProfileParameterDat>& GetInstancePropertiesProfiles();
#endif
#if WITH_EDITORONLY_DATA
CUSTOMIZABLEOBJECT_API TObjectPtr<UEdGraph>& GetSource() const;
CUSTOMIZABLEOBJECT_API FCompilationOptions GetCompileOptions() const;
#endif
CUSTOMIZABLEOBJECT_API void BackwardsCompatibleFixup(int32 CustomizableObjectCustomVersion);
CUSTOMIZABLEOBJECT_API FName GetComponentName(FCustomizableObjectComponentIndex ObjectComponentIndex) const;
#if WITH_EDITORONLY_DATA
CUSTOMIZABLEOBJECT_API EMutableCompileMeshType GetMeshCompileType() const;
CUSTOMIZABLEOBJECT_API const TArray<TSoftObjectPtr<UCustomizableObject>>& GetWorkingSet() const;
CUSTOMIZABLEOBJECT_API bool IsAssetUserDataMergeEnabled() const;
CUSTOMIZABLEOBJECT_API bool IsTableMaterialsParentCheckDisabled() const;
CUSTOMIZABLEOBJECT_API bool IsRealTimeMorphTargetsEnabled() const;
CUSTOMIZABLEOBJECT_API bool IsClothingEnabled() const;
CUSTOMIZABLEOBJECT_API bool Is16BitBoneWeightsEnabled() const;
CUSTOMIZABLEOBJECT_API bool IsAltSkinWeightProfilesEnabled() const;
CUSTOMIZABLEOBJECT_API bool IsPhysicsAssetMergeEnabled() const;
CUSTOMIZABLEOBJECT_API bool IsEnabledAnimBpPhysicsAssetsManipulation() const;
#endif
CUSTOMIZABLEOBJECT_API const FString& GetIntParameterAvailableOption(int32 ParamIndex, int32 K) const;
CUSTOMIZABLEOBJECT_API int32 GetEnumParameterNumValues(int32 ParamIndex) const;
CUSTOMIZABLEOBJECT_API FString FindIntParameterValueName(int32 ParamIndex, int32 ParamValue) const;
CUSTOMIZABLEOBJECT_API int32 FindState(const FString& Name) const;
CUSTOMIZABLEOBJECT_API int32 GetStateParameterIndex(int32 StateIndex, int32 ParameterIndex) const;
CUSTOMIZABLEOBJECT_API bool IsParameterMultidimensional(const int32& InParamIndex) const;
/** Cache of generated SkeletalMeshes */
FMeshCache MeshCache;
/** Cache of merged Skeletons */
FSkeletonCache SkeletonCache;
// See UCustomizableObjectSystem::LockObject. Must only be modified from the game thread
bool bLocked = false;
#if WITH_EDITORONLY_DATA
UPROPERTY()
TArray<FMutableMeshComponentData> MutableMeshComponents_DEPRECATED;
/** Unique Identifier - Deterministic. Used to locate Model and Streamable data on disk. Should not be modified. */
FGuid Identifier;
ECompilationResultPrivate CompilationResult = ECompilationResultPrivate::Unknown;
FPostCompileDelegate PostCompileDelegate;
/** Map of PlatformName to CachedPlatformData. Only valid while cooking. */
TMap<FString, MutablePrivate::FMutableCachedPlatformData> CachedPlatformsData;
#endif
FCustomizableObjectStatus Status;
// This is information about the parameters in the model that is generated at model compile time.
UPROPERTY(Transient)
TArray<FMutableModelParameterProperties> ParameterProperties;
/** Reference to all UObject used in game. Only updated during the compilation if the user explicitly wants to save all references. */
UPROPERTY()
TObjectPtr<UModelResources> ReferencedObjects;
// Map of name to index of ParameterProperties.
// use this to lookup fast by Name
TMap<FString, FMutableParameterIndex> ParameterPropertiesLookupTable;
#if WITH_EDITORONLY_DATA
UPROPERTY()
ECustomizableObjectTextureCompression TextureCompression = ECustomizableObjectTextureCompression::Fast;
/** From 0 to UE_MUTABLE_MAX_OPTIMIZATION */
UPROPERTY()
int32 OptimizationLevel = UE_MUTABLE_MAX_OPTIMIZATION;
/** Use the disk to store intermediate compilation data. This slows down the object compilation
* but it may be necessary for huge objects. */
UPROPERTY()
bool bUseDiskCompilation = false;
/** High limit of the size in bytes of the packaged data when cooking this object.
* This limit is before any pak or filesystem compression. This limit will be broken if a single piece of data is bigger because data is not fragmented for packaging purposes. */
UPROPERTY()
uint64 PackagedDataBytesLimit = 256 * 1024 * 1024;
/** High (inclusive) limit of the size in bytes of a data block to be included into the compiled object directly instead of stored in a streamable file. */
UPROPERTY()
uint64 EmbeddedDataBytesLimit = 1024;
UPROPERTY()
int32 ImageTiling = 0;
#endif
static constexpr int32 DerivedDataVersion = 0x1a376aa8;
};
#if WITH_EDITOR
/** Returns the DDC ValueId of the file owning a streamable resource.
* @ param StreamableDataType - UE level data type
* @ param ResourceType - mu::EDataType
*/
CUSTOMIZABLEOBJECT_API UE::DerivedData::FValueId GetDerivedDataValueIdForResource(MutablePrivate::EStreamableDataType StreamableDataType, uint32 FileId, uint16 ResourceType, uint16 Flags);
// Compose folder name where the data is stored
CUSTOMIZABLEOBJECT_API FString GetCompiledDataFolderPath();
CUSTOMIZABLEOBJECT_API FString GetDataTypeExtension(MutablePrivate::EStreamableDataType DataType);
CUSTOMIZABLEOBJECT_API uint32 GetECustomizableObjectVersionEnumHash();
CUSTOMIZABLEOBJECT_API TObjectPtr<UModelResources> LoadModelResources_Internal(FArchive& Ar, const UCustomizableObject* Outer, const ITargetPlatform* InTargetPlatform, bool bSkipEditorOnlyData = false);
CUSTOMIZABLEOBJECT_API const TSharedPtr<FModelStreamableBulkData> LoadModelStreamableBulk_Internal(FArchive& Ar);
CUSTOMIZABLEOBJECT_API const TSharedPtr<mu::FModel, ESPMode::ThreadSafe> LoadModel_Internal(FArchive& Ar);
#endif