Initial commit: Vertical Partition Streaming plugin (UE 5.7)
Bounded vertical route partition / streaming for handcrafted spiral climb maps (Only Up / Only Climb). Not World Partition, not Level Instances as core arch. - Z-cell segmentation + optional XY subcells, editor builder + commandlet - NonDestructive visibility backend + streaming-level backend - Offline HLOD proxies: MergedMesh / SimplifiedProxy (ProxyLOD) - Universal Level Instance + Packed Level Actor + HISM support (flatten+merge) - Vertical-aware runtime streamer (full/preload/HLOD/unload, hysteresis, velocity prediction, fall-risk), WP-style debug viz + vp.* console - Safe-by-default: only static decor streams; sky/lights/gameplay stay persistent Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1005
Source/VerticalPartitionEditor/Private/VerticalPartitionBuilder.cpp
Normal file
1005
Source/VerticalPartitionEditor/Private/VerticalPartitionBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,62 @@
|
||||
// Copyright IHY. Vertical Partition Streaming plugin (editor module).
|
||||
#include "VerticalPartitionCommandlet.h"
|
||||
#include "VerticalPartitionBuilder.h"
|
||||
#include "VerticalPartitionVolume.h"
|
||||
#include "VerticalPartitionLog.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "Engine/World.h"
|
||||
#include "FileHelpers.h"
|
||||
#include "Misc/PackageName.h"
|
||||
#include "UObject/Package.h"
|
||||
|
||||
UVerticalPartitionCommandlet::UVerticalPartitionCommandlet()
|
||||
{
|
||||
IsClient = false;
|
||||
IsServer = false;
|
||||
IsEditor = true;
|
||||
LogToConsole = true;
|
||||
}
|
||||
|
||||
int32 UVerticalPartitionCommandlet::Main(const FString& Params)
|
||||
{
|
||||
FString MapPath;
|
||||
if (!FParse::Value(*Params, TEXT("Map="), MapPath) || MapPath.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Error, TEXT("[VP] Commandlet requires -Map=/Game/Maps/MyMap"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] Commandlet loading map %s ..."), *MapPath);
|
||||
UWorld* World = UEditorLoadingAndSavingUtils::LoadMap(MapPath);
|
||||
if (!World)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Error, TEXT("[VP] Failed to load map %s"), *MapPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
AVerticalPartitionVolume* Volume = nullptr;
|
||||
for (TActorIterator<AVerticalPartitionVolume> It(World); It; ++It)
|
||||
{
|
||||
Volume = *It;
|
||||
break;
|
||||
}
|
||||
if (!Volume)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Error, TEXT("[VP] No AVerticalPartitionVolume in %s"), *MapPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FVerticalPartitionBuildReport Report;
|
||||
const bool bOk = UVerticalPartitionBuilder::Build(Volume, Report);
|
||||
UVerticalPartitionBuilder::DumpReport(Report, FPackageName::GetShortName(MapPath));
|
||||
|
||||
if (bOk)
|
||||
{
|
||||
TArray<UPackage*> ToSave;
|
||||
ToSave.Add(World->GetOutermost());
|
||||
FEditorFileUtils::PromptForCheckoutAndSave(ToSave, /*bCheckDirty*/false, /*bPromptToSave*/false);
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] Commandlet build OK: %d cells."), Report.GeneratedCells);
|
||||
}
|
||||
|
||||
return bOk ? 0 : 1;
|
||||
}
|
||||
@ -0,0 +1,264 @@
|
||||
// Copyright IHY. Vertical Partition Streaming plugin (editor module).
|
||||
//
|
||||
// Installs the runtime->editor bridge so the volume's CallInEditor buttons and the
|
||||
// vp.* build console commands reach UVerticalPartitionBuilder. Also implements the
|
||||
// editor-only chunk preview.
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "VerticalPartitionVolume.h"
|
||||
#include "VerticalPartitionBuilder.h"
|
||||
#include "VerticalPartitionDescriptor.h"
|
||||
#include "VerticalPartitionStatics.h"
|
||||
#include "VerticalPartitionLog.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/StaticMesh.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "DrawDebugHelpers.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "Misc/PackageName.h"
|
||||
#include "UObject/Package.h"
|
||||
|
||||
static const FName VPPreviewTag(TEXT("VPHLODPreview"));
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "Editor.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
void LogReport(const FVerticalPartitionBuildReport& R, const TCHAR* Title)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] %s: scanned=%d inside=%d excluded=%d cells=%d empty=%d warn=%d err=%d largest=%s(%d)"),
|
||||
Title, R.TotalActorsScanned, R.ActorsInsideVolume, R.ActorsExcluded, R.GeneratedCells, R.EmptyCells,
|
||||
R.WarningCount, R.ErrorCount, *R.LargestCell.ToString(), R.LargestCellActorCount);
|
||||
|
||||
if (GEngine)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan,
|
||||
FString::Printf(TEXT("VP %s: %d cells, %d warnings, %d errors"), Title, R.GeneratedCells, R.WarningCount, R.ErrorCount));
|
||||
}
|
||||
for (const FVerticalPartitionWarning& W : R.Warnings)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Warning, TEXT("[VP] WARN [%s] %s"), *UVerticalPartitionStatics::WarningTypeToString(W.Type), *W.Message);
|
||||
}
|
||||
for (const FVerticalPartitionError& E : R.Errors)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Error, TEXT("[VP] ERR [%s] %s"), *UVerticalPartitionStatics::WarningTypeToString(E.Type), *E.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Persistent coloured cell boxes. GREEN = cell has a baked HLOD proxy, ORANGE = cell
|
||||
// has streamed actors but no proxy (it will just hide when far), GREY = empty Z slice.
|
||||
void PreviewChunks(AVerticalPartitionVolume* Volume)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
if (!Volume || !GEditor) { return; }
|
||||
UWorld* World = GEditor->GetEditorWorldContext().World();
|
||||
if (!World) { return; }
|
||||
|
||||
const FVerticalPartitionSettings& S = Volume->Settings;
|
||||
const FBox Bounds = Volume->GetVolumeBounds();
|
||||
UVerticalPartitionDescriptor* Desc = Volume->Descriptor.LoadSynchronous();
|
||||
|
||||
FlushPersistentDebugLines(World);
|
||||
DrawDebugBox(World, Bounds.GetCenter(), Bounds.GetExtent(), FColor::Cyan, true, -1.f, 0, 30.f);
|
||||
|
||||
const int32 NumZ = UVerticalPartitionStatics::GetNumZCells(Bounds, S);
|
||||
int32 CellsWithHLOD = 0;
|
||||
for (int32 Z = 0; Z < NumZ; ++Z)
|
||||
{
|
||||
const FVerticalCellId Id(0, 0, Z);
|
||||
const FBox CB = UVerticalPartitionStatics::GetCellBounds(Id, Bounds, S);
|
||||
|
||||
int32 Actors = 0;
|
||||
bool bHasCell = false;
|
||||
bool bHasHLOD = false;
|
||||
if (Desc)
|
||||
{
|
||||
for (const FVerticalCellDescriptor& CD : Desc->Cells)
|
||||
{
|
||||
if (CD.CellId.Z == Z)
|
||||
{
|
||||
bHasCell = true;
|
||||
Actors += CD.ActorCount;
|
||||
if (CD.HLODProxyAsset.IsValid()) { bHasHLOD = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bHasHLOD) { ++CellsWithHLOD; }
|
||||
|
||||
const FColor Color = !bHasCell ? FColor(90, 90, 90)
|
||||
: (bHasHLOD ? FColor(40, 200, 80) : FColor(235, 140, 30));
|
||||
DrawDebugBox(World, CB.GetCenter(), CB.GetExtent(), Color, true, -1.f, 0, 12.f);
|
||||
|
||||
const FString Label = bHasCell
|
||||
? FString::Printf(TEXT("Z%d %s actors:%d"), Z, bHasHLOD ? TEXT("[HLOD]") : TEXT("[no-HLOD]"), Actors)
|
||||
: FString::Printf(TEXT("Z%d (empty/persistent)"), Z);
|
||||
DrawDebugString(World, CB.GetCenter(), Label, nullptr, Color, -1.f, true);
|
||||
}
|
||||
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] Preview: %d Z cells (%s). GREEN=HLOD proxy, ORANGE=streamed/no-proxy, GREY=empty. %d cells have a proxy. Use 'Clear Preview' to remove."),
|
||||
NumZ, Desc ? TEXT("from descriptor") : TEXT("no descriptor yet — Build first for HLOD colours"), CellsWithHLOD);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 ClearPreviewActors(UWorld* World)
|
||||
{
|
||||
int32 Removed = 0;
|
||||
#if WITH_EDITOR
|
||||
if (!World) { return 0; }
|
||||
for (TActorIterator<AStaticMeshActor> It(World); It; ++It)
|
||||
{
|
||||
if (It->ActorHasTag(VPPreviewTag))
|
||||
{
|
||||
It->Destroy();
|
||||
++Removed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return Removed;
|
||||
}
|
||||
|
||||
void ClearPreview(AVerticalPartitionVolume* Volume)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
if (!GEditor) { return; }
|
||||
UWorld* World = GEditor->GetEditorWorldContext().World();
|
||||
if (!World) { return; }
|
||||
FlushPersistentDebugLines(World);
|
||||
const int32 Removed = ClearPreviewActors(World);
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] Preview cleared (%d HLOD preview actors removed)."), Removed);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Spawn the baked proxy meshes as temporary editor actors so the HLOD geometry is
|
||||
// directly visible in the viewport. They sit exactly over the source (pivot-at-zero),
|
||||
// so hide the real decor to compare. Tagged + transient; removed by Clear Preview.
|
||||
void SpawnHLODPreview(AVerticalPartitionVolume* Volume)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
if (!Volume || !GEditor) { return; }
|
||||
UWorld* World = GEditor->GetEditorWorldContext().World();
|
||||
if (!World) { return; }
|
||||
|
||||
UVerticalPartitionDescriptor* Desc = Volume->Descriptor.LoadSynchronous();
|
||||
if (!Desc)
|
||||
{
|
||||
UE_LOG(LogVerticalPartition, Warning, TEXT("[VP] SpawnHLODPreview: no descriptor — run Build first."));
|
||||
return;
|
||||
}
|
||||
|
||||
ClearPreviewActors(World);
|
||||
|
||||
int32 Spawned = 0;
|
||||
for (const FVerticalCellDescriptor& CD : Desc->Cells)
|
||||
{
|
||||
if (!CD.HLODProxyAsset.IsValid()) { continue; }
|
||||
UStaticMesh* Mesh = Cast<UStaticMesh>(CD.HLODProxyAsset.TryLoad());
|
||||
if (!Mesh) { continue; }
|
||||
|
||||
FActorSpawnParameters Params;
|
||||
Params.ObjectFlags |= RF_Transient;
|
||||
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||
AStaticMeshActor* Actor = World->SpawnActor<AStaticMeshActor>(FVector::ZeroVector, FRotator::ZeroRotator, Params);
|
||||
if (!Actor) { continue; }
|
||||
|
||||
Actor->Tags.Add(VPPreviewTag);
|
||||
Actor->SetActorLabel(FString::Printf(TEXT("VP_HLODPreview_Z%d"), CD.CellId.Z));
|
||||
if (UStaticMeshComponent* Comp = Actor->GetStaticMeshComponent())
|
||||
{
|
||||
Comp->SetMobility(EComponentMobility::Movable);
|
||||
Comp->SetStaticMesh(Mesh);
|
||||
Comp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
++Spawned;
|
||||
}
|
||||
|
||||
UE_LOG(LogVerticalPartition, Log, TEXT("[VP] Spawned %d HLOD proxy preview actors (tag '%s'). Hide your static decor to compare; 'Clear Preview' removes them."),
|
||||
Spawned, *VPPreviewTag.ToString());
|
||||
if (GEngine)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Green, FString::Printf(TEXT("VP: %d HLOD proxy preview actors spawned"), Spawned));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HandleAction(AVerticalPartitionVolume* Volume, EVerticalPartitionAction Action)
|
||||
{
|
||||
if (!Volume) { return; }
|
||||
FVerticalPartitionBuildReport Report;
|
||||
switch (Action)
|
||||
{
|
||||
case EVerticalPartitionAction::Analyze:
|
||||
Report = UVerticalPartitionBuilder::AnalyzeCurrentLevel(Volume);
|
||||
LogReport(Report, TEXT("Analyze"));
|
||||
break;
|
||||
case EVerticalPartitionAction::Build:
|
||||
UVerticalPartitionBuilder::Build(Volume, Report);
|
||||
LogReport(Report, TEXT("Build"));
|
||||
break;
|
||||
case EVerticalPartitionAction::RebuildChangedCells:
|
||||
UVerticalPartitionBuilder::RebuildChangedCells(Volume, Report);
|
||||
LogReport(Report, TEXT("Rebuild"));
|
||||
break;
|
||||
case EVerticalPartitionAction::RebuildHLOD:
|
||||
UVerticalPartitionBuilder::RebuildHLOD(Volume, Report);
|
||||
LogReport(Report, TEXT("RebuildHLOD"));
|
||||
break;
|
||||
case EVerticalPartitionAction::Validate:
|
||||
Report = UVerticalPartitionBuilder::ValidateCells(Volume);
|
||||
LogReport(Report, TEXT("Validate"));
|
||||
break;
|
||||
case EVerticalPartitionAction::PreviewChunks:
|
||||
PreviewChunks(Volume);
|
||||
break;
|
||||
case EVerticalPartitionAction::SpawnHLODPreview:
|
||||
SpawnHLODPreview(Volume);
|
||||
break;
|
||||
case EVerticalPartitionAction::ClearPreview:
|
||||
ClearPreview(Volume);
|
||||
break;
|
||||
case EVerticalPartitionAction::ClearGenerated:
|
||||
UVerticalPartitionBuilder::ClearGenerated(Volume);
|
||||
break;
|
||||
case EVerticalPartitionAction::Commit:
|
||||
UVerticalPartitionBuilder::CommitConversion(Volume, Report);
|
||||
LogReport(Report, TEXT("Commit"));
|
||||
break;
|
||||
case EVerticalPartitionAction::RestoreBackup:
|
||||
UVerticalPartitionBuilder::RestoreFromBackup(Volume->GetWorld());
|
||||
break;
|
||||
case EVerticalPartitionAction::DumpReport:
|
||||
if (UVerticalPartitionDescriptor* Desc = Volume->Descriptor.LoadSynchronous())
|
||||
{
|
||||
const FString Map = Volume->GetWorld() ? FPackageName::GetShortName(Volume->GetWorld()->GetOutermost()->GetName()) : TEXT("Map");
|
||||
UVerticalPartitionBuilder::DumpReport(Desc->LastReport, Map);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FVerticalPartitionEditorModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FVerticalPartitionEditorBridge::Handler = [](AVerticalPartitionVolume* Volume, EVerticalPartitionAction Action)
|
||||
{
|
||||
HandleAction(Volume, Action);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void ShutdownModule() override
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FVerticalPartitionEditorBridge::Handler = nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_MODULE(FVerticalPartitionEditorModule, VerticalPartitionEditor);
|
||||
@ -0,0 +1,89 @@
|
||||
// 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<AActor> 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<TWeakObjectPtr<AActor>> 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/<Map>_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<FVerticalActorAssignment>& 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<FVerticalActorAssignment>& 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<AActor*>& CellActors, const FVerticalPartitionSettings& S,
|
||||
const FString& PackageRoot, FVerticalPartitionBuildReport& Report);
|
||||
|
||||
static int64 ComputeContentHash(const TArray<FVerticalActorAssignment>& Assignments);
|
||||
static bool SaveAsset(UObject* Asset);
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
// Copyright IHY. Vertical Partition Streaming plugin (editor module).
|
||||
//
|
||||
// Offline build entry point:
|
||||
// UnrealEditor-Cmd.exe Project.uproject -run=VerticalPartition -Map=/Game/Maps/MyMap
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Commandlets/Commandlet.h"
|
||||
#include "VerticalPartitionCommandlet.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UVerticalPartitionCommandlet : public UCommandlet
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UVerticalPartitionCommandlet();
|
||||
|
||||
virtual int32 Main(const FString& Params) override;
|
||||
};
|
||||
@ -0,0 +1,37 @@
|
||||
// Copyright IHY. Vertical Partition Streaming plugin (editor module).
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class VerticalPartitionEditor : ModuleRules
|
||||
{
|
||||
public VerticalPartitionEditor(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"VerticalPartition",
|
||||
});
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[]
|
||||
{
|
||||
"UnrealEd",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"InputCore",
|
||||
"EditorSubsystem",
|
||||
"ToolMenus",
|
||||
"Projects",
|
||||
"AssetRegistry",
|
||||
"AssetTools",
|
||||
"MeshMergeUtilities",
|
||||
"MeshDescription",
|
||||
"StaticMeshDescription",
|
||||
"MaterialUtilities",
|
||||
"MeshReductionInterface",
|
||||
"LevelEditor",
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user