When IOStore is enabled, -createchunkinstall does not exclude non-chunk-0 .utoc/.ucas files from the final package

I was looking to exclude non-chunk-0 pak/.utoc/.ucas files from the IPA generated by an iOS build for my project. I initially found this tutorial page https://dev.epicgames.com/community/learning/tutorials/vwx7/unreal-engine-excluding-chunks-from-ios-builds mentioning that for iOS you needed to add the following parameters to the build command

-chunkinstalldirectory="/Users/Shared/Projects/ChunkTest/CDNChunks" -chunkinstallversion=1.0

But the page also mentioned: “Unfortunately, this does not seem to be aware of the IO Store system that generates a corresponding utoc and ucas file for each pak file, and does not exclude those files from the pak. It does work correctly if you disable the IO Store under Project Settings -> Packaging.”

I then found this old EpicProSupport post [Content removed] which seems to have been the inspiration for the Tutorial page, and in it Jack Porter mentioned: “I am working on a fix to copy and exclude the utoc and ucas files but until it’s available I suggest you try without IOStore enabled.” He also entered ticket UE-172550 to fix the IOStore issue. I went and checked the ticket https://issues.unrealengine.com/issue/UE-172550 and the associated fix commit in UE 5.3 and saw that the fix copied the .utoc/.ucas files to the chunk output directory but did nothing to exclude them from the final build.

I am therefore proposing the following change to the Engine\Source\Programs\AutomationTool\Scripts\CopyBuildToStagingDirectory.Automation.cs script to actually exclude the non-chunk-0 .utoc/.ucas files from the packaged build when running -createchunkinstall with IOStore enabled:

//copy the pak chunk to the raw data folder
InternalUtils.SafeDeleteFile(RawDataPakPath, true);
InternalUtils.SafeDeleteFile(Path.ChangeExtension(RawDataPakPath, ".sig"), true);

// BEGIN CHANGE
// Delete the .utoc and .ucas files from the chunkinstalldirectory in case they are still around from a prior run
InternalUtils.SafeDeleteFile(Path.ChangeExtension(RawDataPakPath, ".utoc"), true);
InternalUtils.SafeDeleteFile(Path.ChangeExtension(RawDataPakPath, ".ucas"), true);
// END CHANGE

InternalUtils.SafeCreateDirectory(RawDataPath, true);
InternalUtils.SafeCopyFile(OutputLocation.FullName, RawDataPakPath);
if (bPakFilesAreSigned)
{
	InternalUtils.SafeCopyFile(Path.ChangeExtension(OutputLocation.FullName, ".sig"), Path.ChangeExtension(RawDataPakPath, ".sig"), true);
}
if (bShouldCreateIoStoreContainerFiles)
{
	InternalUtils.SafeCopyFile(Path.ChangeExtension(OutputLocation.FullName, ".utoc"), Path.ChangeExtension(RawDataPakPath, ".utoc"), true);
	InternalUtils.SafeCopyFile(Path.ChangeExtension(OutputLocation.FullName, ".ucas"), Path.ChangeExtension(RawDataPakPath, ".ucas"), true);

	// BEGIN CHANGE
	// Delete the .utoc and .ucas files from the output directory after having copied them to the chunkinstalldirectory in the
	// context of a createchunkinstall build so they don't end up in the Catalyst\Content\Paks\ directory of the final build.
	InternalUtils.SafeDeleteFile(Path.ChangeExtension(OutputLocation.FullName, ".utoc"), true);
	InternalUtils.SafeDeleteFile(Path.ChangeExtension(OutputLocation.FullName, ".ucas"), true);
	// END CHANGE

	// Check if the optional .uondemandtoc file exists before trying to copy it
	string OnDemandTocSrcPath = Path.ChangeExtension(OutputLocation.FullName, ".uondemandtoc");
	if (File.Exists(OnDemandTocSrcPath))
	{
		InternalUtils.SafeCopyFile(OnDemandTocSrcPath, Path.ChangeExtension(RawDataPakPath, ".uondemandtoc"), true);
	}
}
InternalUtils.SafeDeleteFile(OutputLocation.FullName, true);

It might be worth considering making the same change for the .uondemandtoc file as well while you are at it (I did not include that fix in my snippet).

Steps to Reproduce

  1. Create a Blueprint project and configure it so that certain assets are in different chunks or use the attached ChunkTest.zip repro project
  2. Package the project with the following command (update paths based on your setup):
    1. Engine\Build\BatchFiles\RunUAT.bat BuildCookRun -nop4 -utf8output -nocompileeditor -skipbuildeditor -cook -project=“C:/Projects/ChunkTest/ChunkTest.uproject” -unrealexe=“C:\UE5Main\Engine\Binaries\Win64\UnrealEditor-Cmd.exe” -platform=Win64 -installed -SkipCookingErrorSummary -JsonStdOut -stage -archive -package -pak -iostore -compressed -prereqs -archivedirectory=“C:/BuildOutput” -clientconfig=“Development” -nocompile -nocompileuat -manifests -createchunkinstall -chunkinstalldirectory=“C:/BuildOutput/CDNChunks” -chunkinstallversion=1.0
  3. Check the generated “C:/BuildOutput/CDNChunks” and C:/BuildOutput/Windows" directories under “”
  4. The “C:/BuildOutput/CDNChunks/Windows/1.0/pakchunk1001” folder contains the chunk 1001 pak/utoc/ucas files, and the "“C:/BuildOutput/Windows/ChunkTest/Content/Paks” folder contains chunk 0 pak/ucas/utoc files (expected) as well as chunk 1001 utoc/ucas files (unexpected since we would want them to be excluded the same way the chunk 1001 pak file is).

Hi Bernard,

Thank you for bringing this to our attention. We will run this by the team and let you know if there is a CL associated with your proposed changes.

Best regards.

Hi Bernard,

Your proposed changes were looked, approved by the team and further expanded on. The official CL is here.

Thank you for the report.

You’re very welcome Bernard, thank you for bringing this to our attention.

Best regards.

Hey there! Were you able to find anything on this? (Sorry for the poke but this report request was going to get closed automatically if I didn’t respond).

Awesome stuff! Thanks for the follow up!