EM_Task/CoreUObject/Private/AssetRegistry/AssetBundleData.cpp

279 lines
7.3 KiB
C++
Raw Permalink Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AssetRegistry/AssetBundleData.h"
#include "AssetRegistry/AssetData.h"
#include "UObject/PropertyPortFlags.h"
IMPLEMENT_STRUCT(AssetBundleData);
namespace UE
{
namespace AssetBundleEntry
{
namespace Private
{
const FStringView BundleNamePrefix(TEXT("(BundleName=\""));
const FStringView BundleAssetsPrefix(TEXT(",BundleAssets=("));
const FStringView BundleAssetsSuffix(TEXT("))"));
const FStringView BundlesPrefix(TEXT("(Bundles=("));
const FStringView BundlesSuffix(TEXT("))"));
const FStringView EmptyBundles(TEXT("(Bundles=)"));
static bool SkipPrefix(const TCHAR*& InOutIt, FStringView Prefix)
{
const bool bOk = FStringView(InOutIt, Prefix.Len()) == Prefix;
if (bOk)
{
InOutIt += Prefix.Len();
}
return bOk;
}
} // namespace Private
} // namespace AssetBundleEntry
} // namespace UE
bool FAssetBundleEntry::ExportTextItem(FString& ValueStr, const FAssetBundleEntry& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
if (DefaultValue.IsValid())
{
// This path does not handle default values, fall back to normal export path
return false;
}
using namespace UE::AssetBundleEntry::Private;
const uint32 OriginalLen = ValueStr.Len();
ValueStr += BundleNamePrefix;
BundleName.AppendString(ValueStr);
ValueStr += '\"';
ValueStr += BundleAssetsPrefix;
const FSoftObjectPath EmptyPath;
for (const FSoftObjectPath& Path: BundleAssets)
{
if (!Path.ExportTextItem(ValueStr, EmptyPath, Parent, PortFlags, ExportRootScope))
{
ValueStr.LeftInline(OriginalLen);
return false;
}
ValueStr.AppendChar(',');
}
// Remove last comma
ValueStr.LeftChopInline(1, /* shrink */ false);
ValueStr += BundleAssetsSuffix;
return true;
}
bool FAssetBundleEntry::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText)
{
using namespace UE::AssetBundleEntry::Private;
const TCHAR* BundleNameBegin = Buffer;
if (SkipPrefix(/* in-out */ BundleNameBegin, BundleNamePrefix))
{
if (const TCHAR* BundleNameEnd = FCString::Strchr(BundleNameBegin, TCHAR('"')))
{
FName Name(BundleNameEnd - BundleNameBegin, BundleNameBegin);
const TCHAR* PathIt = BundleNameEnd + 1;
if (SkipPrefix(/* in-out */ PathIt, BundleAssetsPrefix))
{
TArray<FSoftObjectPath> Paths;
while (Paths.Emplace_GetRef().ImportTextItem(/* in-out */ PathIt, PortFlags, Parent, ErrorText))
{
if (*PathIt == ',')
{
++PathIt;
}
else if (SkipPrefix(/* in-out */ PathIt, BundleAssetsSuffix))
{
BundleName = Name;
BundleAssets = MoveTemp(Paths);
Buffer = PathIt;
return true;
}
else
{
return false;
}
}
}
}
}
return false;
}
FAssetBundleEntry* FAssetBundleData::FindEntry(FName SearchName)
{
for (FAssetBundleEntry& Entry: Bundles)
{
if (Entry.BundleName == SearchName)
{
return &Entry;
}
}
return nullptr;
}
void FAssetBundleData::AddBundleAsset(FName BundleName, const FSoftObjectPath& AssetPath)
{
if (!AssetPath.IsValid())
{
return;
}
FAssetBundleEntry* FoundEntry = FindEntry(BundleName);
if (!FoundEntry)
{
FoundEntry = new (Bundles) FAssetBundleEntry(BundleName);
}
FoundEntry->BundleAssets.AddUnique(AssetPath);
}
void FAssetBundleData::AddBundleAssets(FName BundleName, const TArray<FSoftObjectPath>& AssetPaths)
{
FAssetBundleEntry* FoundEntry = FindEntry(BundleName);
for (const FSoftObjectPath& Path: AssetPaths)
{
if (Path.IsValid())
{
// Only create if required
if (!FoundEntry)
{
FoundEntry = new (Bundles) FAssetBundleEntry(BundleName);
}
FoundEntry->BundleAssets.AddUnique(Path);
}
}
}
void FAssetBundleData::SetBundleAssets(FName BundleName, TArray<FSoftObjectPath>&& AssetPaths)
{
FAssetBundleEntry* FoundEntry = FindEntry(BundleName);
if (!FoundEntry)
{
FoundEntry = new (Bundles) FAssetBundleEntry(BundleName);
}
FoundEntry->BundleAssets = AssetPaths;
}
void FAssetBundleData::Reset()
{
Bundles.Reset();
}
bool FAssetBundleData::ExportTextItem(FString& ValueStr, FAssetBundleData const& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
if (Bundles.Num() == 0)
{
// Empty, don't write anything to avoid it cluttering the asset registry tags
return true;
}
else if (DefaultValue.Bundles.Num() != 0)
{
// This path does not handle default values, fall back to normal export path
return false;
}
using namespace UE::AssetBundleEntry::Private;
const uint32 OriginalLen = ValueStr.Len();
ValueStr += BundlesPrefix;
const FAssetBundleEntry EmptyEntry;
for (const FAssetBundleEntry& Entry: Bundles)
{
if (!Entry.ExportTextItem(ValueStr, EmptyEntry, Parent, PortFlags, ExportRootScope))
{
ValueStr.LeftInline(OriginalLen);
return false;
}
ValueStr.AppendChar(',');
}
// Remove last comma
ValueStr.LeftChopInline(1, /* shrink */ false);
ValueStr += BundlesSuffix;
return true;
}
bool FAssetBundleData::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText)
{
if (*Buffer != TEXT('('))
{
// Empty, don't read/write anything
return true;
}
using namespace UE::AssetBundleEntry::Private;
const TCHAR* It = Buffer;
if (SkipPrefix(/* in-out */ It, BundlesPrefix))
{
TArray<FAssetBundleEntry> Entries;
while (Entries.Emplace_GetRef().ImportTextItem(/* in-out */ It, PortFlags, Parent, ErrorText))
{
if (*It == ',')
{
++It;
}
else if (SkipPrefix(/* in-out */ It, BundlesSuffix))
{
Bundles = MoveTemp(Entries);
Buffer = It;
return true;
}
else
{
return false;
}
}
}
return SkipPrefix(/* in-out */ Buffer, EmptyBundles);
}
FString FAssetBundleData::ToDebugString() const
{
TStringBuilder<220> Result;
bool bFirstLine = true;
for (const FAssetBundleEntry& Data: Bundles)
{
if (!bFirstLine)
{
Result.Append(TEXT("\n"));
}
Result.Appendf(TEXT("%s -> (%s)"),
*Data.BundleName.ToString(),
*FString::JoinBy(Data.BundleAssets, TEXT(", "), [](const FSoftObjectPath& LoadBundle)
{
return LoadBundle.ToString();
}));
bFirstLine = false;
}
return Result.ToString();
}