Files
UnrealEngine/Engine/Source/Programs/AutomationTool/AutomationUtils/PackageUtils.cs
2025-05-18 13:04:45 +08:00

119 lines
4.5 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using AutomationTool;
using EpicGames.MCP.Automation;
using UnrealBuildTool;
using System.Diagnostics;
using EpicGames.Core;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using static AutomationTool.CommandUtils;
namespace AutomationTool
{
public partial class PackageUtils
{
private static void UnpakBuild(FileReference ProjectFile, string SourceDirectory, List<string> PakFiles, string TargetDirectory, string CryptoFilename, string AdditionalArgs)
{
if (!CommandUtils.DirectoryExists(SourceDirectory))
{
Logger.LogError("Pak file directory {SourceDirectory} doesn't exist.", SourceDirectory);
return;
}
string UnrealPakExe = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealPak.exe");
CommandUtils.CreateDirectory(TargetDirectory);
string ProjectArg = ProjectFile != null ? ProjectFile.FullName : "";
Parallel.ForEach(PakFiles, pakFile =>
{
string PathFileFullPath = CommandUtils.CombinePaths(SourceDirectory, pakFile);
string UnrealPakCommandLine = string.Format("{0} {1} -Extract {2} -ExtractToMountPoint -cryptokeys=\"{3}\" {4}",
ProjectArg, PathFileFullPath, TargetDirectory, CryptoFilename, AdditionalArgs);
CommandUtils.RunAndLog(CommandUtils.CmdEnv, UnrealPakExe, UnrealPakCommandLine, Options: CommandUtils.ERunOptions.Default | CommandUtils.ERunOptions.UTF8Output | CommandUtils.ERunOptions.SpewIsVerbose);
//CommandUtils.Log(UnrealPakCommandLine);
});
}
private static List<FileInfo>[] SortFilesByPatchLayers(FileInfo[] FileInfoList)
{
int NumLevels = 0;
bool FoundFilesInLevel = true;
while (FoundFilesInLevel)
{
FoundFilesInLevel = false;
string PatchPakSuffix = String.Format("_{0}_P", NumLevels);
if (FileInfoList.Any(fileInfo => Path.GetFileNameWithoutExtension(fileInfo.Name).EndsWith(PatchPakSuffix)))
{
NumLevels++;
FoundFilesInLevel = true;
}
}
List<FileInfo>[] FileList = new List<FileInfo>[NumLevels + 1];
FileList[0] = FileInfoList.Where(fileInfo => !Path.GetFileNameWithoutExtension(fileInfo.Name).EndsWith("_P")).ToList();
for (int PatchLevel = 0; PatchLevel < NumLevels; PatchLevel++)
{
string PatchPakSuffix = String.Format("_{0}_P", NumLevels);
FileList[PatchLevel + 1] = FileInfoList.Where(fileInfo => Path.GetFileNameWithoutExtension(fileInfo.Name).EndsWith(PatchPakSuffix)).ToList();
}
return FileList;
}
private static void GetFileListByPatchLayers(FileInfo[] PakFiles, out List<string>[] PatchLayers)
{
var SortedLayers = SortFilesByPatchLayers(PakFiles);
PatchLayers = SortedLayers.Select(patchLayer => patchLayer.Select(fileInfo => fileInfo.Name).ToList()).ToArray();
}
/// <summary>
/// Extracts all pak files for a given project.
/// </summary>
/// <param name="SourceDirectory">Source file to read paks from</param>
/// <param name="TargetDirectory">Destinaton path where the contents of the pak file will be written</param>
/// <param name="CryptoKeysFilename">Path to the json bloc with keys if encryption is used</param>
/// <param name="AdditionalArgs">Additional args to pass to UnrealPak</param>
/// <param name="bExtractByLayers">Extract as layers. E.g. patch paks will be extracted after the base paks and will overwrite files</param>
/// <param name="ProjectFile">Path to the project file. Can be null if UnrealPak is not built with project specific options or plugins</param>
/// <returns></returns>
public static void ExtractPakFiles(DirectoryInfo SourceDirectory, string TargetDirectory, string CryptoKeysFilename, string AdditionalArgs, bool bExtractByLayers, FileReference ProjectFile=null)
{
var PakFiles = SourceDirectory.GetFiles("*.pak", SearchOption.TopDirectoryOnly);
if (bExtractByLayers)
{
List<string>[] PatchLayers;
GetFileListByPatchLayers(PakFiles, out PatchLayers);
int NumLayers = PatchLayers.Length;
for (int layerIndex = 0; layerIndex < NumLayers; layerIndex++)
{
UnpakBuild(ProjectFile, SourceDirectory.FullName, PatchLayers[layerIndex], TargetDirectory, CryptoKeysFilename, AdditionalArgs);
}
}
else
{
UnpakBuild(ProjectFile, SourceDirectory.FullName, PakFiles.Select(file => file.Name).ToList(), TargetDirectory, CryptoKeysFilename, AdditionalArgs);
}
}
}
}