Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit cbf84f3

Browse files
committed
Added Script Objects, Bulk Data export, Save Package Store Manifest
1 parent b698aba commit cbf84f3

File tree

5 files changed

+200
-31
lines changed

5 files changed

+200
-31
lines changed

Private/CookedAssetWriter.cpp

Lines changed: 145 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
#include "CookedAssetWriter.h"
44
#include "IoStorePackageMap.h"
55
#include "ZenTools.h"
6+
#include "Dom/JsonObject.h"
67
#include "HAL/FileManager.h"
78
#include "Misc/Paths.h"
89
#include "Serialization/LargeMemoryWriter.h"
910
#include "Serialization/MemoryWriter.h"
1011
#include "UObject/Class.h"
1112
#include "UObject/Package.h"
1213
#include "UObject/SoftObjectPath.h"
14+
#include "Misc/FileHelper.h"
15+
#include "Serialization/JsonSerializer.h"
1316

1417
FAssetSerializationWriter::FAssetSerializationWriter( FArchive& Ar, FAssetSerializationContext* Context ) : FArchiveProxy( Ar ), Context( Context )
1518
{
@@ -59,25 +62,101 @@ FCookedAssetWriter::FCookedAssetWriter(const TSharedPtr<FIoStorePackageMap>& InP
5962
{
6063
}
6164

62-
void FCookedAssetWriter::WritePackagesFromContainer( const FIoContainerId& ContainerId )
65+
void FCookedAssetWriter::WritePackagesFromContainer( const TSharedPtr<FIoStoreReader>& Reader )
6366
{
67+
const FIoContainerId ContainerId = Reader->GetContainerId();
6468
UE_LOG( LogIoStoreTools, Display, TEXT("Writing asset files for Container %lld"), ContainerId.Value() );
6569

6670
FPackageContainerMetadata ContainerMetadata;
6771
if ( PackageMap->FindPackageContainerMetadata( ContainerId, ContainerMetadata ) )
6872
{
6973
for ( const FPackageId& PackageId : ContainerMetadata.PackagesInContainer )
7074
{
71-
WriteSinglePackage( PackageId );
75+
WriteSinglePackage( PackageId, false, Reader );
7276
}
7377
for ( const FPackageId& OptionalPackageId : ContainerMetadata.OptionalPackagesInContainer )
7478
{
75-
WriteSinglePackage( OptionalPackageId );
79+
WriteSinglePackage( OptionalPackageId, true, Reader );
7680
}
7781
}
7882
}
7983

80-
void FCookedAssetWriter::WriteSinglePackage( FPackageId PackageId )
84+
void FCookedAssetWriter::WriteGlobalScriptObjects(const TSharedPtr<FIoStoreReader>& Reader) const
85+
{
86+
TIoStatusOr<FIoBuffer> ScriptObjectsBuffer = Reader->Read(CreateIoChunkId(0, 0, EIoChunkType::ScriptObjects), FIoReadOptions());
87+
88+
if ( ScriptObjectsBuffer.IsOk() )
89+
{
90+
const FString ScriptObjectsFilename = FPaths::Combine( RootOutputDir, TEXT("ScriptObjects.bin") );
91+
FFileHelper::SaveArrayToFile( TArrayView<const uint8>( ScriptObjectsBuffer.ValueOrDie().Data(), ScriptObjectsBuffer.ValueOrDie().DataSize() ), *ScriptObjectsFilename );
92+
93+
UE_LOG( LogIoStoreTools, Display, TEXT("Written ScriptObjects chunk to '%s'"), *ScriptObjectsFilename );
94+
}
95+
}
96+
97+
void FCookedAssetWriter::WritePackageStoreManifest() const
98+
{
99+
const FString PackageStoreFilename = RootOutputDir / TEXT("PackageStoreManifest.json");
100+
IFileManager::Get().MakeDirectory( *FPaths::GetPath( PackageStoreFilename ), true );
101+
102+
const TSharedPtr<FJsonObject> RootObject = MakeShared<FJsonObject>();
103+
104+
TStringBuilder<64> ChunkIdStringBuilder;
105+
auto ChunkIdToString = [&ChunkIdStringBuilder](const FIoChunkId& ChunkId)
106+
{
107+
ChunkIdStringBuilder.Reset();
108+
ChunkIdStringBuilder << ChunkId;
109+
return *ChunkIdStringBuilder;
110+
};
111+
112+
TArray<TSharedPtr<FJsonValue>> FilesArray;
113+
for ( const TPair<FIoChunkId, FString>& FilePair : ChunkIdToSavedFileMap )
114+
{
115+
const TSharedPtr<FJsonObject> FileObject = MakeShared<FJsonObject>();
116+
FileObject->SetStringField( TEXT("Path"), FilePair.Value );
117+
FileObject->SetStringField( TEXT("ChunkId"), ChunkIdToString( FilePair.Key ) );
118+
119+
FilesArray.Add( MakeShared<FJsonValueObject>( FileObject ) );
120+
}
121+
RootObject->SetArrayField( TEXT("Files"), FilesArray );
122+
123+
TArray<TSharedPtr<FJsonValue>> PackagesArray;
124+
for ( const TPair<FName, FSavedPackageInfo>& SavedPackageInfo : SavedPackageMap )
125+
{
126+
const TSharedPtr<FJsonObject> PackageObject = MakeShared<FJsonObject>();
127+
PackageObject->SetStringField( TEXT("Name"), SavedPackageInfo.Key.ToString() );
128+
129+
if ( !SavedPackageInfo.Value.ExportBundleChunks.IsEmpty() )
130+
{
131+
TArray<TSharedPtr<FJsonValue>> ExportBundleChunkIdsArray;
132+
for ( const FIoChunkId& ExportBundleChunkId : SavedPackageInfo.Value.ExportBundleChunks )
133+
{
134+
ExportBundleChunkIdsArray.Add( MakeShared<FJsonValueString>( ChunkIdToString( ExportBundleChunkId ) ) );
135+
}
136+
PackageObject->SetArrayField( TEXT("ExportBundleChunkIds"), ExportBundleChunkIdsArray );
137+
}
138+
139+
if ( !SavedPackageInfo.Value.BulkDataChunks.IsEmpty() )
140+
{
141+
TArray<TSharedPtr<FJsonValue>> BulkDataChunkIdsArray;
142+
for ( const FIoChunkId& BulkDataChunkId : SavedPackageInfo.Value.BulkDataChunks )
143+
{
144+
BulkDataChunkIdsArray.Add( MakeShared<FJsonValueString>( ChunkIdToString( BulkDataChunkId ) ) );
145+
}
146+
PackageObject->SetArrayField( TEXT("BulkDataChunkIds"), BulkDataChunkIdsArray );
147+
}
148+
PackagesArray.Add( MakeShared<FJsonValueObject>( PackageObject ) );
149+
}
150+
RootObject->SetArrayField( TEXT("Packages"), PackagesArray );
151+
152+
FString ResultJsonString;
153+
FJsonSerializer::Serialize( RootObject.ToSharedRef(), TJsonWriterFactory<>::Create( &ResultJsonString ) );
154+
155+
check( FFileHelper::SaveStringToFile( ResultJsonString, *PackageStoreFilename ) );
156+
UE_LOG( LogIoStoreTools, Display, TEXT("Written PackageStore Manifest to '%s'"), *PackageStoreFilename );
157+
}
158+
159+
void FCookedAssetWriter::WriteSinglePackage( FPackageId PackageId, bool bIsOptionalSegmentPackage, const TSharedPtr<FIoStoreReader>& Reader )
81160
{
82161
FPackageMapExportBundleEntry ExportBundleEntry;
83162
checkf( PackageMap->FindExportBundleData( PackageId, ExportBundleEntry ), TEXT("Failed to find export bundle entry for PackageId %lld"), PackageId.ValueForDebugging() );
@@ -93,13 +172,24 @@ void FCookedAssetWriter::WriteSinglePackage( FPackageId PackageId )
93172
SerializationContext.PackageId = PackageId;
94173
SerializationContext.PackageHeaderFilename = PackageFilename;
95174
SerializationContext.BundleData = &ExportBundleEntry;
175+
SerializationContext.IoStoreReader = Reader.Get();
176+
177+
FSavedPackageInfo& SavedPackageInfo = SavedPackageMap.FindOrAdd( SerializationContext.BundleData->PackageName );
178+
SavedPackageInfo.ExportBundleChunks.Add( SerializationContext.BundleData->PackageChunkId );
96179

97180
// Populate package summary, and also process imports and exports
98181
ProcessPackageSummaryAndNamesAndExportsAndImports( SerializationContext );
99182

100183
// Serialize exports into the separate file (event driven loader expects that)
101184
{
102-
const FString ExportsFilename = FPaths::ChangeExtension( SerializationContext.PackageHeaderFilename, LexToString( EPackageExtension::Exports ) );
185+
FString ExtensionString = LexToString( EPackageExtension::Exports );
186+
187+
// Optional segment packages have .o prefix before their extensions, e.g.
188+
if ( bIsOptionalSegmentPackage )
189+
{
190+
ExtensionString.InsertAt( 0, TEXT(".o") );
191+
}
192+
const FString ExportsFilename = FPaths::ChangeExtension( SerializationContext.PackageHeaderFilename, ExtensionString );
103193

104194
const TUniquePtr<FArchive> ExportsArchive( IFileManager::Get().CreateFileWriter( *ExportsFilename, FILEWRITE_EvenIfReadOnly ) );
105195
checkf( ExportsArchive.IsValid(), TEXT("Failed to load exports file '%s'"), *ExportsFilename );
@@ -112,7 +202,17 @@ void FCookedAssetWriter::WriteSinglePackage( FPackageId PackageId )
112202
// Serialize package summary and other necessary data into the main asset header file
113203
{
114204
const EPackageExtension HeaderExtension = ( SerializationContext.Summary.GetPackageFlags() & PKG_ContainsMap ) != 0 ? EPackageExtension::Map : EPackageExtension::Asset;
115-
const FString HeaderFilename = FPaths::ChangeExtension( SerializationContext.PackageHeaderFilename, LexToString( HeaderExtension ) );
205+
FString ExtensionString = LexToString( HeaderExtension );
206+
207+
// Optional segment packages have .o prefix before their extensions, e.g.
208+
if ( bIsOptionalSegmentPackage )
209+
{
210+
ExtensionString.InsertAt( 0, TEXT(".o") );
211+
}
212+
const FString HeaderFilename = FPaths::ChangeExtension( SerializationContext.PackageHeaderFilename, ExtensionString );
213+
214+
FString RelativeFilename = FPaths::SetExtension( ExportBundleEntry.PackageFilename, ExtensionString );
215+
ChunkIdToSavedFileMap.Add( SerializationContext.BundleData->PackageChunkId, RelativeFilename );
116216

117217
const TUniquePtr<FArchive> HeaderArchive( IFileManager::Get().CreateFileWriter( *HeaderFilename, FILEWRITE_EvenIfReadOnly ) );
118218
checkf( HeaderArchive.IsValid(), TEXT("Failed to open header file '%s'"), *HeaderFilename );
@@ -122,6 +222,9 @@ void FCookedAssetWriter::WriteSinglePackage( FPackageId PackageId )
122222
HeaderArchive->Flush();
123223
}
124224

225+
// Write bulk data
226+
WriteBulkData( SerializationContext );
227+
125228
// Notify the user that we have finished writing the asset
126229
UE_LOG( LogIoStoreTools, Display, TEXT("Serialized Package '%s' to '%s'"), *SerializationContext.BundleData->PackageName.ToString(), *SerializationContext.PackageHeaderFilename );
127230
NumPackagesWritten++;
@@ -584,8 +687,8 @@ FPackageIndex FCookedAssetWriter::CreateObjectExport( const FPackageMapExportEnt
584687

585688
ObjectExport.ObjectFlags = ExportData.ObjectFlags;
586689

587-
ObjectExport.SerialSize = ExportData.CookedSerialData->Num();
588-
ObjectExport.SerialOffset = -1; // Not resolved yet
690+
ObjectExport.SerialSize = INDEX_NONE;
691+
ObjectExport.SerialOffset = INDEX_NONE;
589692

590693
ObjectExport.bForcedExport = false; // not serialized
591694
ObjectExport.bNotForClient = EnumHasAnyFlags( ExportData.FilterFlags, EExportFilterFlags::NotForClient );
@@ -868,20 +971,51 @@ void FCookedAssetWriter::WritePackageHeader(FArchive& Ar, FAssetSerializationCon
868971

869972
void FCookedAssetWriter::WritePackageExports(FArchive& Ar, FAssetSerializationContext& Context)
870973
{
974+
// Open the package bundle chunk to read exports
975+
TIoStatusOr<FIoBuffer> ChunkBuffer = Context.IoStoreReader->Read( Context.BundleData->PackageChunkId, FIoReadOptions() );
976+
check( ChunkBuffer.IsOk() );
977+
const uint8* ChunkDataStart = ChunkBuffer.ValueOrDie().Data();
978+
const uint8* ChunkDataEnd = ChunkDataStart + ChunkBuffer.ValueOrDie().DataSize();
979+
871980
// Write export blobs
872981
for ( int32 i = 0; i < Context.ExportMap.Num(); i++ )
873982
{
874-
TArray<uint8>& SerialData = *Context.BundleData->ExportMap[ i ].CookedSerialData;
983+
const FPackageMapExportEntry& OriginalExport = Context.BundleData->ExportMap[ i ];
875984
FObjectExport& Export = Context.ExportMap[ i ];
876985

877986
Export.SerialOffset = Ar.Tell();
878-
Export.SerialSize = SerialData.Num();
987+
Export.SerialSize = OriginalExport.SerialDataSize;
879988

880-
Ar.Serialize( SerialData.GetData(), SerialData.Num() );
989+
const uint8* SerialDataStart = ChunkDataStart + OriginalExport.SerialDataOffset;
990+
check( SerialDataStart <= ChunkDataEnd );
991+
Ar.Serialize( const_cast<uint8*>( SerialDataStart ), OriginalExport.SerialDataSize );
881992
}
882993
Context.Summary.BulkDataStartOffset = Ar.Tell();
883994

884995
// Exports end with the package file tag
885996
uint32 FooterData = PACKAGE_FILE_TAG;
886997
Ar << FooterData;
887998
}
999+
1000+
void FCookedAssetWriter::WriteBulkData( const FAssetSerializationContext& Context )
1001+
{
1002+
FSavedPackageInfo& SavedPackageInfo = SavedPackageMap.FindOrAdd( Context.BundleData->PackageName );
1003+
1004+
for ( const FIoChunkId& BulkDataChunkId : Context.BundleData->BulkDataChunkIds )
1005+
{
1006+
TIoStatusOr<FIoBuffer> BulkDataBuffer = Context.IoStoreReader->Read( BulkDataChunkId, FIoReadOptions() );
1007+
check( BulkDataBuffer.IsOk() );
1008+
1009+
TIoStatusOr<FIoStoreTocChunkInfo> ChunkInfo = Context.IoStoreReader->GetChunkInfo( BulkDataChunkId );
1010+
check( ChunkInfo.IsOk() );
1011+
1012+
FString RelativeFilename = ChunkInfo.ValueOrDie().FileName;
1013+
RelativeFilename.RemoveFromStart( TEXT("../../../") );
1014+
1015+
const FString ResultFilename = FPaths::Combine( RootOutputDir, RelativeFilename );
1016+
FFileHelper::SaveArrayToFile( TArrayView<const uint8>( BulkDataBuffer.ValueOrDie().Data(), BulkDataBuffer.ValueOrDie().DataSize() ), *ResultFilename );
1017+
1018+
ChunkIdToSavedFileMap.Add( BulkDataChunkId, RelativeFilename );
1019+
SavedPackageInfo.BulkDataChunks.Add( BulkDataChunkId );
1020+
}
1021+
}

Private/CookedAssetWriter.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct FAssetSerializationContext
3636
FPackageId PackageId;
3737
FString PackageHeaderFilename;
3838
FPackageMapExportBundleEntry* BundleData;
39+
FIoStoreReader* IoStoreReader;
3940

4041
FPackageFileSummary Summary;
4142
int32 PackageSummaryEndOffset;
@@ -64,20 +65,30 @@ class FAssetSerializationWriter : public FArchiveProxy
6465
virtual void SetFilterEditorOnly(bool InFilterEditorOnly) override;
6566
};
6667

68+
struct FSavedPackageInfo
69+
{
70+
TArray<FIoChunkId> ExportBundleChunks;
71+
TArray<FIoChunkId> BulkDataChunks;
72+
};
73+
6774
class ZENTOOLS_API FCookedAssetWriter
6875
{
6976
protected:
7077
TSharedPtr<FIoStorePackageMap> PackageMap;
7178
FString RootOutputDir;
7279
int32 NumPackagesWritten;
80+
TMap<FIoChunkId, FString> ChunkIdToSavedFileMap;
81+
TMap<FName, FSavedPackageInfo> SavedPackageMap;
7382
public:
7483
FCookedAssetWriter( const TSharedPtr<FIoStorePackageMap>& InPackageMap, const FString& InOutputDir );
7584

76-
void WritePackagesFromContainer( const FIoContainerId& ContainerId );
85+
void WritePackagesFromContainer( const TSharedPtr<FIoStoreReader>& Reader );
86+
void WriteGlobalScriptObjects( const TSharedPtr<FIoStoreReader>& Reader ) const;
87+
void WritePackageStoreManifest() const;
7788

7889
FORCEINLINE int32 GetTotalNumPackagesWritten() const { return NumPackagesWritten; }
7990
private:
80-
void WriteSinglePackage( FPackageId PackageId );
91+
void WriteSinglePackage( FPackageId PackageId, bool bIsOptionalSegmentPackage, const TSharedPtr<FIoStoreReader>& Reader );
8192
void ProcessPackageSummaryAndNamesAndExportsAndImports( FAssetSerializationContext& Context ) const;
8293
static FExportBundleEntry BuildPreloadDependenciesFromExportBundle( int32 ExportBundleIndex, FAssetSerializationContext& Context );
8394
static void BuildPreloadDependenciesFromArcs( FAssetSerializationContext& Context );
@@ -98,4 +109,5 @@ class ZENTOOLS_API FCookedAssetWriter
98109

99110
static void WritePackageHeader( FArchive& Ar, FAssetSerializationContext& Context );
100111
static void WritePackageExports( FArchive& Ar, FAssetSerializationContext& Context );
112+
void WriteBulkData(const FAssetSerializationContext& Context );
101113
};

Private/IoStorePackageMap.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,20 @@ void FIoStorePackageMap::PopulateFromContainer(const TSharedPtr<FIoStoreReader>&
6565

6666
TIoStatusOr<FIoStoreTocChunkInfo> ChunkInfo = Reader->GetChunkInfo( ChunkId );
6767
TIoStatusOr<FIoBuffer> PackageBuffer = Reader->Read( ChunkId, FIoReadOptions() );
68-
69-
if ( PackageBuffer.IsOk() )
68+
check( PackageBuffer.IsOk() );
69+
70+
FPackageMapExportBundleEntry* ExportBundleEntry = ReadExportBundleData( PackageId, ChunkInfo.ValueOrDie(), PackageBuffer.ValueOrDie() );
71+
72+
// Required segment packages can have bulk data, memory mapped bulk data and optional bulk data
73+
const TArray BulkDataChunkTypes{ EIoChunkType::BulkData, EIoChunkType::MemoryMappedBulkData, EIoChunkType::OptionalBulkData };
74+
75+
for ( const EIoChunkType BulkDataChunkType : BulkDataChunkTypes )
7076
{
71-
ReadExportBundleData( PackageId, ChunkInfo.ValueOrDie(), PackageBuffer.ValueOrDie() );
77+
const FIoChunkId BulkDataChunkId = CreateIoChunkId( PackageId.Value(), 0, BulkDataChunkType );
78+
if ( Reader->GetChunkInfo( BulkDataChunkId ).IsOk() )
79+
{
80+
ExportBundleEntry->BulkDataChunkIds.Add( BulkDataChunkId );
81+
}
7282
}
7383
}
7484

@@ -80,10 +90,15 @@ void FIoStorePackageMap::PopulateFromContainer(const TSharedPtr<FIoStoreReader>&
8090

8191
TIoStatusOr<FIoStoreTocChunkInfo> ChunkInfo = Reader->GetChunkInfo( ChunkId );
8292
TIoStatusOr<FIoBuffer> PackageBuffer = Reader->Read( ChunkId, FIoReadOptions() );
93+
check( PackageBuffer.IsOk() );
8394

84-
if ( PackageBuffer.IsOk() )
95+
FPackageMapExportBundleEntry* ExportBundleEntry = ReadExportBundleData( PackageId, ChunkInfo.ValueOrDie(), PackageBuffer.ValueOrDie() );
96+
97+
// Optional segment packages can only have optional segment bulk data
98+
const FIoChunkId BulkDataChunkId = CreateIoChunkId( PackageId.Value(), 1, EIoChunkType::BulkData );
99+
if ( Reader->GetChunkInfo( BulkDataChunkId ).IsOk() )
85100
{
86-
ReadExportBundleData( PackageId, ChunkInfo.ValueOrDie(), PackageBuffer.ValueOrDie() );
101+
ExportBundleEntry->BulkDataChunkIds.Add( BulkDataChunkId );
87102
}
88103
}
89104

@@ -195,7 +210,7 @@ FPackageLocalObjectRef FIoStorePackageMap::ResolvePackageLocalRef( const FPackag
195210
return Result;
196211
}
197212

198-
void FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, const FIoStoreTocChunkInfo& ChunkInfo, const FIoBuffer& ChunkBuffer )
213+
FPackageMapExportBundleEntry* FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, const FIoStoreTocChunkInfo& ChunkInfo, const FIoBuffer& ChunkBuffer )
199214
{
200215
const uint8* PackageSummaryData = ChunkBuffer.Data();
201216
const FZenPackageSummary* PackageSummary = reinterpret_cast<const FZenPackageSummary*>(PackageSummaryData);
@@ -221,6 +236,7 @@ void FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, cons
221236
PackageData.PackageName = PackageName;
222237
PackageData.PackageFlags = PackageSummary->PackageFlags;
223238
PackageData.VersioningInfo = VersioningInfo;
239+
PackageData.PackageChunkId = ChunkInfo.Id;
224240

225241
// get rid of standard filename prefix
226242
PackageData.PackageFilename.RemoveFromStart( TEXT("../../../") );
@@ -279,8 +295,8 @@ void FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, cons
279295
ExportData.SuperIndex = ResolvePackageLocalRef( ExportMapEntry.SuperIndex, PackageHeader.ImportedPackages, ImportedPublicExportHashes );
280296
ExportData.TemplateIndex = ResolvePackageLocalRef( ExportMapEntry.TemplateIndex, PackageHeader.ImportedPackages, ImportedPublicExportHashes );
281297

282-
ExportData.CookedSerialData = MakeShared<TArray<uint8>>();
283-
ExportData.CookedSerialData->SetNumUninitialized(ExportMapEntry.CookedSerialSize);
298+
ExportData.SerialDataSize = ExportMapEntry.CookedSerialSize;
299+
ExportData.SerialDataOffset = INDEX_NONE;
284300
}
285301

286302
// Read export bundles
@@ -303,12 +319,9 @@ void FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, cons
303319

304320
if (BundleEntry->CommandType == FExportBundleEntry::ExportCommandType_Serialize)
305321
{
306-
const FPackageMapExportEntry& Export = PackageData.ExportMap[ BundleEntry->LocalExportIndex ];
307-
const int32 ExportSerialSize = Export.CookedSerialData->Num();
308-
309-
// Copy the export data into the buffer that we have crated earlier
310-
FMemory::Memcpy( Export.CookedSerialData->GetData(), PackageSummaryData + CurrentExportOffset, ExportSerialSize );
311-
CurrentExportOffset += ExportSerialSize;
322+
FPackageMapExportEntry& Export = PackageData.ExportMap[ BundleEntry->LocalExportIndex ];
323+
Export.SerialDataOffset = CurrentExportOffset;
324+
CurrentExportOffset += Export.SerialDataSize;
312325
}
313326
BundleEntry++;
314327
}
@@ -346,4 +359,5 @@ void FIoStorePackageMap::ReadExportBundleData( const FPackageId& PackageId, cons
346359
ArcsAr << ExternalArc.ToExportBundleIndex;
347360
}
348361
}
362+
return &PackageData;
349363
}

0 commit comments

Comments
 (0)