ue5 wp生成cell

发布时间 2023-06-15 19:36:12作者: kk20161206

ue5 wp生成cell

bool UWorldPartition::GenerateStreaming(TArray<FString>* OutPackagesToGenerate)
{
    return GenerateContainerStreaming(ActorDescContainer, OutPackagesToGenerate);
}

bool UWorldPartition::GenerateContainerStreaming(const UActorDescContainer* InActorDescContainer, TArray<FString>* OutPackagesToGenerate /* = nullptr */)
{
    FActorDescList* ModifiedActorsDescList = nullptr;

    FStreamingGenerationLogErrorHandler LogErrorHandler;
    FStreamingGenerationMapCheckErrorHandler MapCheckErrorHandler;    
    IStreamingGenerationErrorHandler* ErrorHandler = &LogErrorHandler;    

    if (bIsPIE)
    {
        ModifiedActorsDescList = &RuntimeHash->ModifiedActorDescListForPIE;
        
        // In PIE, we always want to populate the map check dialog
        ErrorHandler = &MapCheckErrorHandler;
    }

    // Dump state log
    const TCHAR* StateLogSuffix = bIsPIE ? TEXT("PIE") : (IsRunningGame() ? TEXT("Game") : (IsRunningCookCommandlet() ? TEXT("Cook") : TEXT("Manual")));
    TUniquePtr<FArchive> LogFileAr = FWorldPartitionStreamingGenerator::CreateDumpStateLogArchive(StateLogSuffix);
    FHierarchicalLogArchive HierarchicalLogAr(*LogFileAr);

    FWorldPartitionStreamingGenerator StreamingGenerator(ModifiedActorsDescList, ErrorHandler, IsStreamingEnabled());

    // Preparation Phase
    StreamingGenerator.PreparationPhase(InActorDescContainer);

    StreamingGenerator.DumpStateLog(HierarchicalLogAr);

    // Generate streaming
    check(!StreamingPolicy);
    StreamingPolicy = NewObject<UWorldPartitionStreamingPolicy>(const_cast<UWorldPartition*>(this), WorldPartitionStreamingPolicyClass.Get(), NAME_None, bIsPIE ? RF_Transient : RF_NoFlags);

    check(RuntimeHash);
    if (RuntimeHash->GenerateStreaming(StreamingPolicy, StreamingGenerator.GetStreamingGenerationContext(), OutPackagesToGenerate))
    {
        //if (IsRunningCookCommandlet())
        {
            RuntimeHash->DumpStateLog(HierarchicalLogAr);
        }

        StreamingPolicy->PrepareActorToCellRemapping();
        return true;
    }

    return false;
}

调用generateStream的函数:

TArray<ICookPackageSplitter::FGeneratedPackage> FWorldPartitionCookPackageSplitter::GetGenerateList(const UPackage* OwnerPackage, const UObject* OwnerObject)
{
    // TODO: Make WorldPartition functions const so we can honor the constness of the OwnerObject in this API function
    const UWorld* ConstPartitionedWorld = ValidateDataObject(OwnerObject);
    UWorld* PartitionedWorld = const_cast<UWorld*>(ConstPartitionedWorld);

    // Store the World pointer to declare it to GarbageCollection; we do not want to allow the World to be Garbage Collected
    // until we have finished all of our PreSaveGeneratedPackage calls, because we store information on the World 
    // that is necessary for populate 
    ReferencedWorld = PartitionedWorld;

    check(!bInitializedPhysicsSceneForSave && !bForceInitializedWorld);
    bInitializedPhysicsSceneForSave = GEditor->InitializePhysicsSceneForSaveIfNecessary(PartitionedWorld, bForceInitializedWorld);

    // Manually initialize WorldPartition
    UWorldPartition* WorldPartition = PartitionedWorld->PersistentLevel->GetWorldPartition();
    // We expect the WorldPartition has not yet been initialized
    ensure(!WorldPartition->IsInitialized());
    WorldPartition->Initialize(PartitionedWorld, FTransform::Identity);
    bInitializedWorldPartition = true;

    TArray<FString> WorldPartitionGeneratedPackages;
    WorldPartition->GenerateStreaming(&WorldPartitionGeneratedPackages);

    TArray<ICookPackageSplitter::FGeneratedPackage> PackagesToGenerate;
    PackagesToGenerate.Reserve(WorldPartitionGeneratedPackages.Num());
    for (const FString& PackageName : WorldPartitionGeneratedPackages)
    {
        ICookPackageSplitter::FGeneratedPackage& GeneratedPackage = PackagesToGenerate.Emplace_GetRef();
        GeneratedPackage.RelativePath = PackageName;
        GeneratedPackage.GeneratedRootPath = OwnerPackage->GetName();
        // all packages we generate get a ULevel from CreateEmptyLevelForRuntimeCell and are hence maps
        GeneratedPackage.SetCreateAsMap(true);
        // @todo_ow: Set dependencies once we get iterative cooking working
    }
    return PackagesToGenerate;
}

和UWorldPartition的beginPlay函数。editor下的函数。

前者被调用

bool FGeneratorPackage::TryGenerateList(UObject* OwnerObject, FPackageDatas& PackageDatas)里。
被调用:
UE::Cook::EPollStatus UCookOnTheFlyServer::QueueGeneratedPackages(UE::Cook::FGeneratorPackage& Generator,
    UE::Cook::FPackageData& PackageData)
{
    using namespace UE::Cook;

    ICookPackageSplitter* Splitter = Generator.GetCookPackageSplitterInstance();
    UObject* SplitObject = Generator.FindSplitDataObject();
    FCookGenerationInfo& Info = Generator.GetOwnerInfo();
    if (!SplitObject)
    {
        UE_LOG(LogCook, Error, TEXT("Could not find SplitDataObject %s"), *Generator.GetSplitDataObjectName().ToString());
        return EPollStatus::Error;
    }

    if (Info.GetSaveState() <= FCookGenerationInfo::ESaveState::GenerateList)
    {
        // Call the splitter to generate the list
        if (!Generator.TryGenerateList(SplitObject, *PackageDatas))
        {
            return EPollStatus::Error;
        }

被调用:

UE::Cook::EPollStatus UCookOnTheFlyServer::PrepareSaveInternal(UE::Cook::FPackageData& PackageData,
UE::Cook::FCookerTimer& Timer, bool bPrecaching)
{
被调用
UE::Cook::EPollStatus UCookOnTheFlyServer::PrepareSave(UE::Cook::FPackageData& PackageData,
UE::Cook::FCookerTimer& Timer, bool bPrecaching)
UE::Cook::EPollStatus UCookOnTheFlyServer::PrepareSaveInternal(UE::Cook::FPackageData& PackageData,
UE::Cook::FCookerTimer& Timer, bool bPrecaching)

 
结构
/**
 * Helper that wraps a ICookPackageSplitter, gets/caches packages to generate and provide
 * the necessary to iterate over all of them iteratively.
 */
struct FGeneratorPackage
{
public:
    /** Store the provided CookPackageSplitter and prepare the packages to generate. */
    FGeneratorPackage(UE::Cook::FPackageData& InOwner, const UObject* InSplitDataObject,
        ICookPackageSplitter* InCookPackageSplitterInstance);
    ~FGeneratorPackage();
    /** Clear references to owned generated packages, and mark those packages as orphaned */
    void ClearGeneratedPackages();

    /** Call the Splitter's GetGenerateList and create the PackageDatas */
    bool TryGenerateList(UObject* OwnerObject, FPackageDatas& PackageDatas);

    /** Accessor for the packages to generate */
    TArrayView<UE::Cook::FCookGenerationInfo> GetPackagesToGenerate() { return PackagesToGenerate; }
    /** Return the GenerationInfo used to save the Generator's UPackage */
    UE::Cook::FCookGenerationInfo& GetOwnerInfo() { return OwnerInfo; }
    /** Return owner FPackageData. */
    UE::Cook::FPackageData& GetOwner() { return *OwnerInfo.PackageData; }
    /** Return the GenerationInfo for the given PackageData, or null if not found. */
    UE::Cook::FCookGenerationInfo* FindInfo(const FPackageData& PackageData);
    const UE::Cook::FCookGenerationInfo* FindInfo(const FPackageData& PackageData) const;

    /** Return CookPackageSplitter. */
    ICookPackageSplitter* GetCookPackageSplitterInstance() const { return CookPackageSplitterInstance.Get(); }
    /** Return the SplitDataObject's FullObjectPath. */
    const FName GetSplitDataObjectName() const { return SplitDataObjectName; }
    /**
     * Find again the split object from its name, or return null if no longer in memory.
     * It may have been GC'd and reloaded since the last time we used it.
     */
    UObject* FindSplitDataObject() const;

    void ResetSaveState(FCookGenerationInfo& Info, UPackage* Package, UE::Cook::EReleaseSaveReason ReleaseSaveReason);

    int32& GetNextPopulateIndex() { return NextPopulateIndex; }

    /** Callbacks during garbage collection */
    void PreGarbageCollect(FCookGenerationInfo& Info, TArray<UObject*>& GCKeepObjects,
        TArray<UPackage*>& GCKeepPackages, TArray<FPackageData*>& GCKeepPackageDatas, bool& bOutShouldDemote);
    void PostGarbageCollect();

    /** Call CreatePackage and set PackageData for deterministic generated packages, and update status. */
    UPackage* CreateGeneratedUPackage(FCookGenerationInfo& GenerationInfo,
        const UPackage* OwnerPackage, const TCHAR* GeneratedPackageName);
    /** Mark that the generator or a generated package has saved, to keep track of when *this is no longer needed. */
    void SetPackageSaved(FCookGenerationInfo& Info, FPackageData& PackageData);
    /** Return whether list has been generated and all generated packages have been populated */
    bool IsComplete() const;

    void UpdateSaveAfterGarbageCollect(const FPackageData& PackageData, bool& bInOutDemote);

    UPackage* GetOwnerPackage() const { return OwnerPackage.Get(); };
    void SetOwnerPackage(UPackage* InPackage) { OwnerPackage = InPackage; }

private:
    void ConditionalNotifyCompletion(ICookPackageSplitter::ETeardown Status);

    /** PackageData for the package that is being split */
    FCookGenerationInfo OwnerInfo;
    /** Name of the object that prompted the splitter creation */
    FName SplitDataObjectName;
    /** Cached CookPackageSplitter */
    TUniquePtr<ICookPackageSplitter> CookPackageSplitterInstance;
    /** Recorded list of packages to generate from the splitter, and data we need about them */
    TArray<FCookGenerationInfo> PackagesToGenerate;
    TWeakObjectPtr<UPackage> OwnerPackage;

    int32 NextPopulateIndex = 0;
    int32 RemainingToPopulate = 0;

    bool bNotifiedCompletion = false;
};