Example #1
0
        /// <summary>
        /// Validates any imported chapter information against the currently detected chapter information in the 
        /// source media. If validation fails then an error message is returned via the out parameter <see cref="validationErrorMessage"/>
        /// </summary>
        /// <param name="importedChapters">The list of imported chapter information</param>
        /// <param name="validationErrorMessage">In case of a validation error this variable will hold 
        ///                                      a detailed message that can be presented to the user</param>
        /// <returns>True if there are no errors with imported chapters, false otherwise</returns>
        private bool ValidateImportedChapters(Dictionary<int, Tuple<string, TimeSpan>> importedChapters, out string validationErrorMessage)
        {
            validationErrorMessage = null;

            // If the number of chapters don't match, prompt for confirmation
            if (importedChapters.Count != this.Task.ChapterNames.Count)
            {
                if (MessageBoxResult.Yes !=
                    this.errorService.ShowMessageBox(
                        string.Format(Resources.ChaptersViewModel_ValidateImportedChapters_ChapterCountMismatchMsg, this.Task.ChapterNames.Count, importedChapters.Count),
                        Resources.ChaptersViewModel_ValidateImportedChapters_ChapterCountMismatchWarning,
                        MessageBoxButton.YesNo,
                        MessageBoxImage.Question))
                {
                    return false;
                }
            }

            // If the average discrepancy in timings between chapters is either:
            //   a) more than 15 sec for more than 2 chapters
            //      (I chose 15sec based on empirical evidence from testing a few DVDs and comparing to chapter-marker files I downloaded)
            //      => This check will not be performed for the first and last chapter as they're very likely to differ significantly due to language and region
            //         differences (e.g. longer title sequences and different distributor credits)
            var diffs = importedChapters.Zip(this.Task.ChapterNames, (import, source) => source.Duration - import.Value.Item2);
            if (diffs.Count(diff => Math.Abs(diff.TotalSeconds) > 15) > 2)
            {
                if (MessageBoxResult.Yes !=
                    this.errorService.ShowMessageBox(
                        Resources.ChaptersViewModel_ValidateImportedChapters_ChapterDurationMismatchMsg,
                        Resources.ChaptersViewModel_ValidateImportedChapters_ChapterDurationMismatchWarning,
                        MessageBoxButton.YesNo,
                        MessageBoxImage.Question))
                {
                    return false;
                }
            }

            // All is well, we should import chapters
            return true;
        }
	/// <summary>
	/// Creates pak files using streaming install chunk manifests.
	/// </summary>
	/// <param name="Params"></param>
	/// <param name="SC"></param>
	private static void CreatePaksUsingChunkManifests(ProjectParams Params, DeploymentContext SC)
	{
		Log("Creating pak using streaming install manifests.");
		DumpManifest(SC, CombinePaths(CmdEnv.LogFolder, "PrePak" + (SC.DedicatedServer ? "_Server" : "")));

		var TmpPackagingPath = GetTmpPackagingPath(Params, SC);
		var ChunkListFilename = GetChunkPakManifestListFilename(Params, SC);
		var ChunkList = ReadAllLines(ChunkListFilename);
		var ChunkResponseFiles = new HashSet<string>[ChunkList.Length];
		for (int Index = 0; Index < ChunkList.Length; ++Index)
		{
			var ChunkManifestFilename = CombinePaths(TmpPackagingPath, ChunkList[Index]);
			ChunkResponseFiles[Index] = ReadPakChunkManifest(ChunkManifestFilename);
		}
		// We still want to have a list of all files to stage. We will use the chunk manifests
		// to put the files from staging manigest into the right chunk
		var StagingManifestResponseFile = CreatePakResponseFileFromStagingManifest(SC);
		// DefaultChunkIndex assumes 0 is the 'base' chunk
		const int DefaultChunkIndex = 0;
		var PakResponseFiles = new Dictionary<string, string>[ChunkList.Length];
		for (int Index = 0; Index < PakResponseFiles.Length; ++Index)
		{
			PakResponseFiles[Index] = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
		}
		foreach (var StagingFile in StagingManifestResponseFile)
		{
			bool bAddedToChunk = false;
			for (int ChunkIndex = 0; !bAddedToChunk && ChunkIndex < ChunkResponseFiles.Length; ++ChunkIndex)
			{
                		string OriginalFilename = StagingFile.Key;
                		string NoExtension = CombinePaths(Path.GetDirectoryName(OriginalFilename), Path.GetFileNameWithoutExtension(OriginalFilename));
                		string OriginalReplaceSlashes = OriginalFilename.Replace('/', '\\');
                		string NoExtensionReplaceSlashes = NoExtension.Replace('/', '\\');

				if (ChunkResponseFiles[ChunkIndex].Contains(OriginalFilename) || 
                		    ChunkResponseFiles[ChunkIndex].Contains(OriginalReplaceSlashes) ||
		                    ChunkResponseFiles[ChunkIndex].Contains(NoExtension) ||
		                    ChunkResponseFiles[ChunkIndex].Contains(NoExtensionReplaceSlashes))
				{
					PakResponseFiles[ChunkIndex].Add(StagingFile.Key, StagingFile.Value);
					bAddedToChunk = true;
				}
			}
			if (!bAddedToChunk)
			{
				//Log("No chunk assigned found for {0}. Using default chunk.", StagingFile.Key);
				PakResponseFiles[DefaultChunkIndex].Add(StagingFile.Key, StagingFile.Value);
			}
		}

		if (Params.CreateChunkInstall)
		{
			string ManifestDir = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform, "ManifestDir");
			if (InternalUtils.SafeDirectoryExists(ManifestDir))
			{
				foreach (string ManifestFile in Directory.GetFiles(ManifestDir, "*.manifest"))
				{
					InternalUtils.SafeDeleteFile(ManifestFile, true);
				}
			}
			string DestDir = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform, Params.ChunkInstallVersionString);
			if (InternalUtils.SafeDirectoryExists(DestDir))
			{
				InternalUtils.SafeDeleteDirectory(DestDir); 
			}
		}

		IEnumerable<Tuple<Dictionary<string,string>, string>> PakPairs = PakResponseFiles.Zip(ChunkList, (a, b) => Tuple.Create(a, b));

        if (Params.CreateChunkInstall)
        {
            string ChunkInstallBasePath = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform);
            string CloudDir = MakePathSafeToUseWithCommandLine(CombinePaths(ChunkInstallBasePath, "CloudDir"));
            InternalUtils.SafeDeleteDirectory(CloudDir, true);
        }

        System.Threading.Tasks.Parallel.ForEach(PakPairs, (PakPair) =>
		{
			var ChunkName = Path.GetFileNameWithoutExtension(PakPair.Item2);
			CreatePak(Params, SC, PakPair.Item1, ChunkName, Params.SignPak);
		});

		String ChunkLayerFilename = CombinePaths(GetTmpPackagingPath(Params, SC), GetChunkPakLayerListName());
		String OutputChunkLayerFilename = Path.Combine(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "ChunkLayerInfo", GetChunkPakLayerListName());
		Directory.CreateDirectory(Path.GetDirectoryName(OutputChunkLayerFilename));
		File.Copy(ChunkLayerFilename, OutputChunkLayerFilename, true);
	}