BrawlBuilder.BrawlBuilder.CopyModFiles C# (CSharp) Method

CopyModFiles() private method

private CopyModFiles ( ) : bool
return bool
		private bool CopyModFiles()
		{
			if (Directory.Exists(modFolder.Text))
			{
				// If the mod contains stages (actually just alt stages) then we have to do some preparation
				if (Directory.Exists(modFolder.Text + @"\stage\melee"))
				{
					SetStatus("Preparing...");

					// The first thing we want to do is get a list of all alt stages included in the mod. This is to resolve the problem described here: https://github.com/mogzol/BrawlBuilder/issues/4#issuecomment-245806404
					// We will use that list to create duplicates of the original .rel files for each alternate stage prior to copying over any files.
					IEnumerable<string> altStages = Directory.EnumerateFiles(modFolder.Text + @"\stage\melee")
						.Where(f => Regex.IsMatch(f, @"_[A-Z]\.pac$", RegexOptions.IgnoreCase));

					foreach (string stage in altStages)
					{
						Regex altStageMatcher = new Regex(@"melee\" + Path.DirectorySeparatorChar + "(STG.+?)(?:_.+|LV[0-9])?(_[A-Z]).pac$", RegexOptions.IgnoreCase);
						Match match = altStageMatcher.Match(stage);

						string baseName = match.Groups[1].Value;
						string altCode = match.Groups[2].Value;
						string relPath = @"ssbb.d\files\module\" + pacRelMappings[baseName];

						if (File.Exists(relPath + ".rel") && !File.Exists(relPath + altCode + ".rel"))
							File.Copy(relPath + ".rel", relPath + altCode + ".rel");
					}
				}

				SetStatus("Copying...");

				// Get absolute paths to the mod files
				string[] modFilesAbsolute = Directory.GetFiles(modFolder.Text, "*", SearchOption.AllDirectories);

				_progress = 0;
				_progressMax = modFilesAbsolute.Length;

				blinker.RunWorkerAsync();

				Uri relative = new Uri(modFolder.Text);
				foreach (string absoluteFile in modFilesAbsolute)
				{
					// Convert to relative path for easy copying
					Uri fileUri = new Uri(absoluteFile);
					string relativeFile = relative.MakeRelativeUri(fileUri).ToString();

					// relativeFile will still have base folder at this point, so lets remove that
					// First remove leading slash. I think at this point all slashes will be forward slashes, and it wont start with a slash, but w/e
					if (relativeFile.StartsWith("/") || relativeFile.StartsWith("\\"))
						relativeFile = relativeFile.Substring(1);

					// Now remove base folder
					relativeFile = relativeFile.Substring(relativeFile.IndexOfAny(new char[] { '/', '\\' }));

					// Some files need _en added to the end, check in ssbb.d for that
					bool needs_en = false;
					string relativeFile_en;
					if (relativeFile.Contains('.'))
						relativeFile_en = relativeFile.Substring(0, relativeFile.LastIndexOf('.')) + "_en" + relativeFile.Substring(relativeFile.LastIndexOf('.'), relativeFile.Length - relativeFile.LastIndexOf('.'));
					else
						relativeFile_en = relativeFile + "_en";

					// Check brawl files for match with _en, if found then set needs_en to true
					if (File.Exists(@"ssbb.d\files" + relativeFile_en))
						needs_en = true;

					// Perform copy
					Directory.CreateDirectory(@"ssbb.d\files" + Path.GetDirectoryName(relativeFile)); // Just in case it doesn't already exist

					// If remove_en was set in the CodePatches.txt file, then remove _en suffixes
					if (_remove_en)
					{
						File.Copy(absoluteFile, @"ssbb.d\files" + relativeFile, true);
						File.Delete(@"ssbb.d\files" + relativeFile_en); // Get rid of those pesky space-wasting _en files, we don't need em here
					}
					else
					{
						File.Copy(absoluteFile, needs_en ? @"ssbb.d\files" + relativeFile_en : @"ssbb.d\files" + relativeFile, true);
					}

					_progress++;

					if (buildWorker.CancellationPending)
					{
						blinker.CancelAsync();

						// Since we have been copying files in, ssbb.d is no longer a clean Brawl. Delete it.
						DeleteBrawlFolder();

						return false;
					}
				}

				// Stop blinker before continuing
				blinker.CancelAsync();
				while (blinker.IsBusy)
					Thread.Sleep(100);

				// Base stage files need to be padded to be the same size as their largest alt stage
				// If there aren't alt stages this will do nothing
				if (!Environment.GetCommandLineArgs().Contains("--no-alt-pad"))
				{
					string[] stages = Directory.GetFiles(@"ssbb.d\files\stage\melee");

					SetStatus("Padding...");
					_progress = 0;
					_progressMax = stages.Length;
					blinker.RunWorkerAsync();

					foreach (string stage in stages)
					{
						if (!Regex.IsMatch(stage, @"_[A-Z]\.pac$", RegexOptions.IgnoreCase)) // If not an alt stage
						{
							string filename = Path.GetFileNameWithoutExtension(stage);

							// Select all the alt stages for this stage
							IEnumerable<string> altStages = stages.Where(s => Regex.IsMatch(s, filename + @"_[A-Z]\.pac$", RegexOptions.IgnoreCase));

							// Determine the largest one (resharper converted my foreach loop. LINQ is cool.)
							long largest = altStages.Select(altStage => new FileInfo(altStage).Length).DefaultIfEmpty(0).Max();

							// If base stage is smaller, add padding to match largest alt stage
							long baseStageSize = new FileInfo(stage).Length;
							if (baseStageSize < largest)
							{
								long padding = largest - baseStageSize;

								using (FileStream stream = new FileStream(stage, FileMode.Append))
								{
									stream.Write(new byte[padding], 0, (int)padding); // Just going to cast to an int since I doubt padding will be > 2GB
								}
							}
						}

						_progress++;

						if (buildWorker.CancellationPending)
						{
							blinker.CancelAsync();

							// Since we have been copying files in, ssbb.d is no longer a clean Brawl. Delete it.
							DeleteBrawlFolder();

							return false;
						}
					}

					// Stop blinker before continuing
					blinker.CancelAsync();
					while (blinker.IsBusy)
						Thread.Sleep(100);
				}

				// Finally we need to clean up any extra uneeded alternate stage .rel files (since we made copies of the original for every alt stage)
				// The way we will do this is delete any alternate .rel files that are identical to the base one (since the mod will fall back to the base one anyway)
				IEnumerable<string> altRels = Directory.EnumerateFiles(@"ssbb.d\files\module\").Where(f => Regex.IsMatch(f, @"_[A-Z]\.rel$", RegexOptions.IgnoreCase));

				if (altRels.Any())
				{
					SetStatus("Cleaning Up...");
					_progress = 0;
					_progressMax = altRels.Count();
					blinker.RunWorkerAsync();

					foreach (string altRel in altRels)
					{
						string filename = Path.GetFileNameWithoutExtension(altRel);
						string baseRel = @"ssbb.d\files\module\" + filename.Remove(filename.Length - 2) + ".rel"; // Remove the _[A-Z] part to get the base rel name

						FileInfo baseInfo = new FileInfo(baseRel);

						if (baseInfo.Exists)
						{
							FileInfo altInfo = new FileInfo(altRel);

							// First check if files are the same size. If yes, then check if they are identical.
							if (baseInfo.Length == altInfo.Length && File.ReadAllBytes(baseRel).SequenceEqual(File.ReadAllBytes(altRel)))
								File.Delete(altRel);
						}

						_progress++;

						if (buildWorker.CancellationPending)
						{
							blinker.CancelAsync();

							// Since we have been copying files in, ssbb.d is no longer a clean Brawl. Delete it.
							DeleteBrawlFolder();

							return false;
						}
					}

					// Stop blinker before continuing
					blinker.CancelAsync();
					while (blinker.IsBusy)
						Thread.Sleep(100);
				}
			}
			else
			{
				// Mod folder was selected, but it has been deleted or moved since the initial check
				StopWorker("Mod folder not found, stopping build...");
				return false;
			}

			return true;
		}