Files
Machinist_700km/Plugins/HoudiniEngine/Source/HoudiniEngine/Private/HoudiniPackageParams.cpp
T
Andron666 9c38e93fa4 part7
2022-12-05 20:31:35 +05:00

436 lines
13 KiB
C++

/*
* Copyright (c) <2021> Side Effects Software Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. The name of Side Effects Software may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "HoudiniPackageParams.h"
#include "HoudiniEnginePrivatePCH.h"
#include "HoudiniEngineRuntime.h"
#include "HoudiniEngineUtils.h"
#include "HoudiniStaticMesh.h"
#include "HoudiniStringResolver.h"
#include "PackageTools.h"
#include "ObjectTools.h"
#include "Engine/StaticMesh.h"
#include "UObject/MetaData.h"
//
FHoudiniPackageParams::FHoudiniPackageParams()
{
PackageMode = EPackageMode::CookToTemp;
ReplaceMode = EPackageReplaceMode::ReplaceExistingAssets;
TempCookFolder = FHoudiniEngineRuntime::Get().GetDefaultTemporaryCookFolder();
BakeFolder = FHoudiniEngineRuntime::Get().GetDefaultBakeFolder();
OuterPackage = nullptr;
ObjectName = FString();
HoudiniAssetName = FString();
HoudiniAssetActorName = FString();
ObjectId = 0;
GeoId = 0;
PartId = 0;
SplitStr = 0;
ComponentGUID.Invalidate();
PDGTOPNetworkName.Empty();
PDGTOPNodeName.Empty();
PDGWorkItemIndex = INDEX_NONE;
}
//
FHoudiniPackageParams::~FHoudiniPackageParams()
{
}
// Returns the object flags corresponding to the current package mode
EObjectFlags
FHoudiniPackageParams::GetObjectFlags() const
{
if (PackageMode == EPackageMode::CookToTemp)
return RF_Public | RF_Standalone;
else if (PackageMode == EPackageMode::Bake)
return RF_Public | RF_Standalone;
else
return RF_NoFlags;
}
FString
FHoudiniPackageParams::GetPackageName() const
{
if (!ObjectName.IsEmpty())
return ObjectName;
// If we have PDG infos, generate a name including them
if (!PDGTOPNetworkName.IsEmpty() && !PDGTOPNodeName.IsEmpty() && PDGWorkItemIndex >= 0)
{
return FString::Printf(
TEXT("%s_%s_%s_%d_%d_%s"),
*HoudiniAssetName, *PDGTOPNetworkName, *PDGTOPNodeName, PDGWorkItemIndex, PartId, *SplitStr);
}
else
{
// Generate an object name using the HGPO IDs and the HDA name
return FString::Printf(TEXT("%s_%d_%d_%d_%s"), *HoudiniAssetName, ObjectId, GeoId, PartId, *SplitStr);
}
}
FString
FHoudiniPackageParams::GetPackagePath() const
{
FString PackagePath = FString();
switch (PackageMode)
{
case EPackageMode::CookToLevel:
{
// Path to the persistent level
//PackagePath = FPackageName::GetLongPackagePath(OuterPackage->GetOuter()->GetName());
// In this mode, we'll use the persistent level as our package's outer
// simply use the hda + component guid for the path
// Add a subdir for the HDA
if (!HoudiniAssetName.IsEmpty())
PackagePath += TEXT("/") + HoudiniAssetName;
// Add a subdir using the owner component GUID if possible
if(ComponentGUID.IsValid())
PackagePath += TEXT("/") + ComponentGUID.ToString().Left(PACKAGE_GUID_LENGTH);
// TODO: FIX ME!!!
// Old version
// Build the package name
PackagePath = FPackageName::GetLongPackagePath(OuterPackage->GetOuter()->GetName()) +
TEXT("/") +
HoudiniAssetName;
}
break;
case EPackageMode::CookToTemp:
{
// Temporary Folder
PackagePath = TempCookFolder;
// Add a subdir for the HDA
if (!HoudiniAssetName.IsEmpty())
PackagePath += TEXT("/") + HoudiniAssetName;
// Add a subdir using the owner component GUID if possible
if (ComponentGUID.IsValid())
PackagePath += TEXT("/") + ComponentGUID.ToString().Left(PACKAGE_GUID_LENGTH);
}
break;
case EPackageMode::Bake:
{
PackagePath = BakeFolder;
}
break;
}
return PackagePath;
}
bool
FHoudiniPackageParams::GetBakeCounterFromBakedAsset(const UObject* InAsset, int32& OutBakeCounter)
{
OutBakeCounter = 0;
if (!IsValid(InAsset))
return false;
UPackage* Package = InAsset->GetOutermost();// GetPackage();
// const FString PackagePathName = Package->GetPathName();
// FString PackagePathNamePrefix;
// FString BakeCountOrGUID;
// if (!GetPackageNameWithoutBakeCounterOrGUIDSuffix(PackagePathName, PackagePathNamePrefix, BakeCountOrGUID))
// PackagePathNamePrefix = PackagePathName;
//
// const FString ThisPackageNameBase = UPackageTools::SanitizePackageName(GetPackagePath() + TEXT("/") + GetPackageName());
// if (!PackagePathNamePrefix.Equals(ThisPackageNameBase))
// return false;
//
// // Not a valid counter suffix, could be a GUID suffix. Return true since the prefixes match.
// if (BakeCountOrGUID.IsNumeric())
// OutBakeCounter = FCString::Atoi(*BakeCountOrGUID);
//
// return true;
if (!IsValid(Package))
return false;
UMetaData* MetaData = Package->GetMetaData();
if (!IsValid(MetaData))
return false;
if (MetaData->RootMetaDataMap.Contains(HAPI_UNREAL_PACKAGE_META_BAKE_COUNTER))
{
FString BakeCounterStr = MetaData->RootMetaDataMap.FindChecked(HAPI_UNREAL_PACKAGE_META_BAKE_COUNTER);
BakeCounterStr.TrimStartAndEndInline();
if (BakeCounterStr.IsNumeric())
{
OutBakeCounter = FCString::Atoi(*BakeCounterStr);
return true;
}
}
return false;
}
bool
FHoudiniPackageParams::GetGUIDFromTempAsset(const UObject* InAsset, FString& OutGUID)
{
if (!InAsset)
return false;
UPackage* Package = InAsset->GetOutermost();//GetPackage();
if (!IsValid(Package))
return false;
UMetaData* MetaData = Package->GetMetaData();
if (!IsValid(MetaData))
return false;
if (MetaData->RootMetaDataMap.Contains(HAPI_UNREAL_PACKAGE_META_TEMP_GUID))
{
OutGUID = MetaData->RootMetaDataMap.FindChecked(HAPI_UNREAL_PACKAGE_META_TEMP_GUID);
OutGUID.TrimStartAndEndInline();
if (!OutGUID.IsEmpty())
return true;
}
return false;
}
FString
FHoudiniPackageParams::GetPackageNameExcludingBakeCounter(const UObject* InAsset)
{
if (!IsValid(InAsset))
return FString();
UPackage* Package = InAsset->GetOutermost();
if (!IsValid(Package))
return FString();
FString PackageName = FPaths::GetCleanFilename(Package->GetPathName());
int32 BakeCounter = 0;
if (GetBakeCounterFromBakedAsset(InAsset, BakeCounter))
{
const FString BakeCounterSuffix = FString::Printf(TEXT("_%d"), BakeCounter);
if (PackageName.EndsWith(BakeCounterSuffix))
PackageName = PackageName.Mid(0, PackageName.Len() - BakeCounterSuffix.Len());
}
return PackageName;
}
bool
FHoudiniPackageParams::MatchesPackagePathNameExcludingBakeCounter(const UObject* InAsset) const
{
if (!IsValid(InAsset))
return false;
UPackage* Package = InAsset->GetOutermost();//GetPackage();
if (!IsValid(Package))
return false;
const FString InAssetPackagePathName = FPaths::GetPath(Package->GetPathName()) + TEXT("/") + GetPackageNameExcludingBakeCounter(InAsset);
const FString ThisPackagePathName = UPackageTools::SanitizePackageName(GetPackagePath() + TEXT("/") + GetPackageName());
return InAssetPackagePathName.Equals(ThisPackagePathName);
}
FString
FHoudiniPackageParams::GetPackageNameExcludingGUID(const UObject* InAsset)
{
if (!IsValid(InAsset))
return FString();
UPackage* Package = InAsset->GetOutermost();
if (!IsValid(Package))
return FString();
FString PackageName = FPaths::GetCleanFilename(Package->GetPathName());
FString GUIDStr;
if (GetGUIDFromTempAsset(InAsset, GUIDStr))
{
if (PackageName.EndsWith(TEXT("_") + GUIDStr))
PackageName = PackageName.Mid(0, PackageName.Len() - GUIDStr.Len() - 1);
}
return PackageName;
}
UPackage*
FHoudiniPackageParams::CreatePackageForObject(FString& OutPackageName, int32 InBakeCounterStart) const
{
// GUID/counter used to differentiate with existing package
int32 BakeCounter = InBakeCounterStart;
FGuid CurrentGuid = FGuid::NewGuid();
// Get the appropriate package path/name for this object
FString PackageName = GetPackageName();
FString PackagePath = GetPackagePath();
// Iterate until we find a suitable name for the package
UPackage * NewPackage = nullptr;
while (true)
{
OutPackageName = PackageName;
// Append the Bake guid/counter to the object name if needed
if (BakeCounter > 0)
{
OutPackageName += (PackageMode == EPackageMode::Bake)
? TEXT("_") + FString::FromInt(BakeCounter)
: TEXT("_") + CurrentGuid.ToString().Left(PACKAGE_GUID_LENGTH);
}
// Build the final package name
FString FinalPackageName = PackagePath + TEXT("/") + OutPackageName;
// Sanitize package name.
FinalPackageName = UPackageTools::SanitizePackageName(FinalPackageName);
UObject * PackageOuter = nullptr;
if (PackageMode == EPackageMode::CookToLevel)
{
// If we are not baking, then use outermost package, since objects within our package
// need to be visible to external operations, such as copy paste.
PackageOuter = OuterPackage;
}
// If we are set to create new assets, check if a package named similarly already exists
if (ReplaceMode == EPackageReplaceMode::CreateNewAssets)
{
UPackage* FoundPackage = FindPackage(PackageOuter, *FinalPackageName);
if (FoundPackage == nullptr)
{
// Package might not be in memory, check if it exists on disk
FoundPackage = LoadPackage(Cast<UPackage>(PackageOuter), *FinalPackageName, LOAD_Verify | LOAD_NoWarn);
}
if (FoundPackage && !FoundPackage->IsPendingKill())
{
// we need to generate a new name for it
CurrentGuid = FGuid::NewGuid();
BakeCounter++;
continue;
}
}
// Create actual package.
NewPackage = CreatePackage(PackageOuter, *FinalPackageName);
if (IsValid(NewPackage))
{
// Record bake counter / temp GUID in package metadata
UMetaData* MetaData = NewPackage->GetMetaData();
if (IsValid(MetaData))
{
if (PackageMode == EPackageMode::Bake)
{
// HOUDINI_LOG_MESSAGE(TEXT("Recording bake counter in package metadata: %d"), BakeCounter);
MetaData->RootMetaDataMap.Add(
HAPI_UNREAL_PACKAGE_META_BAKE_COUNTER, FString::FromInt(BakeCounter));
}
else if (CurrentGuid.IsValid())
{
const FString GuidStr = CurrentGuid.ToString().Left(PACKAGE_GUID_LENGTH);
// HOUDINI_LOG_MESSAGE(TEXT("Recording temp guid in package metadata: %s"), *GuidStr);
MetaData->RootMetaDataMap.Add(HAPI_UNREAL_PACKAGE_META_TEMP_GUID, GuidStr);
}
}
}
break;
}
return NewPackage;
}
// Fixes link error with the template function under
void TemplateFixer()
{
FHoudiniPackageParams PP;
UStaticMesh* SM = PP.CreateObjectAndPackage<UStaticMesh>();
UHoudiniStaticMesh* HSM = PP.CreateObjectAndPackage<UHoudiniStaticMesh>();
//UMaterial* Mat = PP.CreateObjectAndPackage<UMaterial>();
//UTexture2D* Text = PP.CreateObjectAndPackage<UTexture2D>();
}
template<typename T>
T* FHoudiniPackageParams::CreateObjectAndPackage()
{
// Create the package for the object
FString NewObjectName;
UPackage* Package = CreatePackageForObject(NewObjectName);
if (!Package || Package->IsPendingKill())
return nullptr;
const FString SanitizedObjectName = ObjectTools::SanitizeObjectName(NewObjectName);
T* ExistingTypedObject = FindObject<T>(Package, *NewObjectName);
UObject* ExistingObject = FindObject<UObject>(Package, *NewObjectName);
if (ExistingTypedObject != nullptr && !ExistingTypedObject->IsPendingKill())
{
// An object of the appropriate type already exists, update it!
ExistingTypedObject->PreEditChange(nullptr);
}
else if (ExistingObject != nullptr)
{
// Replacing an object of a different type, Delete it first.
const bool bDeleteSucceeded = ObjectTools::DeleteSingleObject(ExistingObject);
if (bDeleteSucceeded)
{
// Force GC so we can cleanly create a new asset (and not do an 'in place' replacement)
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
// Create a package for each mesh
Package = CreatePackageForObject(NewObjectName);
if (!Package || Package->IsPendingKill())
return nullptr;
}
else
{
// failed to delete
return nullptr;
}
}
// Add meta information to this package.
FHoudiniEngineUtils::AddHoudiniMetaInformationToPackage(
Package, Package, HAPI_UNREAL_PACKAGE_META_GENERATED_OBJECT, TEXT("true"));
FHoudiniEngineUtils::AddHoudiniMetaInformationToPackage(
Package, Package, HAPI_UNREAL_PACKAGE_META_GENERATED_NAME, *NewObjectName);
return NewObject<T>(Package, FName(*SanitizedObjectName), GetObjectFlags());
}