// Copyright IHY. Vertical Partition Streaming plugin (editor module). // // Editor-only conversion pipeline: scan -> validate -> assign -> generate // descriptor -> generate HLOD proxies -> (optionally) bake streaming sub-levels. #pragma once #include "CoreMinimal.h" #include "UObject/Object.h" #include "VerticalPartitionTypes.h" #include "VerticalPartitionBuilder.generated.h" class AVerticalPartitionVolume; class UVerticalPartitionDescriptor; class UWorld; class AActor; /** One actor's analysed placement, shared between Analyze and Build. */ struct FVerticalActorAssignment { TWeakObjectPtr Actor; /** The renderable static-decor leaf actors this unit streams. For a normal actor this * is just [Actor]; for a Level Instance it is its (recursively flattened) static child * actors; for a Packed Level Actor it is [Actor] (its baked HISM live on it). */ TArray> LeafActors; FVerticalCellId Cell; FBox Bounds = FBox(ForceInit); bool bCrossesMultiple = false; bool bExcluded = false; bool bLargeKeepPersistent = false; }; UCLASS() class UVerticalPartitionBuilder : public UObject { GENERATED_BODY() public: /** Scan the level, classify every actor, return a report without writing anything. */ static FVerticalPartitionBuildReport AnalyzeCurrentLevel(AVerticalPartitionVolume* Volume); /** Full build: analyze -> create/refresh descriptor -> generate HLOD proxies -> * (DestructiveCommit only) bake streaming sub-levels + remove source actors. * Returns the report; writes the descriptor asset. */ static bool Build(AVerticalPartitionVolume* Volume, FVerticalPartitionBuildReport& OutReport); /** Re-run only cells whose source content hash changed since the last build. */ static bool RebuildChangedCells(AVerticalPartitionVolume* Volume, FVerticalPartitionBuildReport& OutReport); /** (Re)generate HLOD proxy meshes for all cells. */ static bool RebuildHLOD(AVerticalPartitionVolume* Volume, FVerticalPartitionBuildReport& OutReport); /** Re-run analysis against the existing descriptor and flag drift / problems. */ static FVerticalPartitionBuildReport ValidateCells(AVerticalPartitionVolume* Volume); /** Promote a NonDestructive descriptor to baked streaming sub-levels. */ static bool CommitConversion(AVerticalPartitionVolume* Volume, FVerticalPartitionBuildReport& OutReport); static bool CreateBackup(UWorld* World, FString& OutBackupPath); static bool RestoreFromBackup(UWorld* World); /** Delete generated descriptor / cell maps / proxies under the output root. */ static void ClearGenerated(AVerticalPartitionVolume* Volume); /** Write the report to Saved/VerticalPartition/_Report.txt and log it. */ static FString DumpReport(const FVerticalPartitionBuildReport& Report, const FString& MapName); private: // ---- pipeline steps ---- static void GatherActors(AVerticalPartitionVolume* Volume, const FBox& VolumeBounds, TArray& OutAssignments, FVerticalPartitionBuildReport& Report); static void ClassifyActorWarnings(const FVerticalActorAssignment& A, const FVerticalPartitionSettings& S, FVerticalPartitionBuildReport& Report); static UVerticalPartitionDescriptor* CreateOrLoadDescriptor(AVerticalPartitionVolume* Volume); static void BuildCells(AVerticalPartitionVolume* Volume, const FBox& VolumeBounds, const TArray& Assignments, UVerticalPartitionDescriptor* Descriptor, FVerticalPartitionBuildReport& Report); /** Generate one proxy mesh for a cell from its static-mesh actors. Returns the * asset path or an empty path (with a warning) on failure / unavailable API. */ static FSoftObjectPath GenerateHLODProxyForCell(const FVerticalCellId& Cell, const TArray& CellActors, const FVerticalPartitionSettings& S, const FString& PackageRoot, FVerticalPartitionBuildReport& Report); static int64 ComputeContentHash(const TArray& Assignments); static bool SaveAsset(UObject* Asset); };