9 public static class ModMerger
11 public static void AskMerge(ContentPackage[] mods)
13 ErrorIfNonLocal(mods);
15 var msgBox =
new GUIMessageBox(TextManager.Get(
"MergeModsHeader"),
"", relativeSize: (0.5f, 0.8f),
16 buttons:
new LocalizedString[] { TextManager.Get(
"ConfirmModMerge"), TextManager.Get(
"Cancel") });
17 msgBox.Buttons[1].OnClicked = msgBox.Close;
19 var desc =
new GUITextBlock(
new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform), TextManager.Get(
"MergeModsDesc"));
20 var modsList =
new GUIListBox(
new RectTransform((1.0f, 0.5f), msgBox.Content.RectTransform))
22 OnSelected = (component, o) =>
false,
25 foreach (var mod
in mods)
27 new GUITextBlock(
new RectTransform((1.0f, 0.11f), modsList.Content.RectTransform), mod.Name)
32 var footer =
new GUITextBlock(
new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform), TextManager.Get(
"MergeModsFooter"));
33 var resultName =
new GUITextBox(
new RectTransform((1.0f, 0.1f), msgBox.Content.RectTransform))
35 Text = (mods.Count(m => m.Files.Length > 1)==1)
36 ? mods.First(m => m.Files.Length > 1).Name
43 resultName.Flash(GUIStyle.Red);
46 msgBox.Buttons[0].OnClicked = (button, o) =>
48 if (
string.IsNullOrEmpty(resultName.Text))
53 string targetDir = $
"{ContentPackage.LocalModsDir}/{resultName.Text}";
55 bool dirMatches(ContentPackage mod)
56 => mod.Dir.CleanUpPathCrossPlatform(correctFilenameCase:
false)
57 .Equals(targetDir, StringComparison.OrdinalIgnoreCase);
58 if (ContentPackageManager.LocalPackages.Any(dirMatches)
59 && !mods.Any(dirMatches))
65 MergeMods(mods, resultName.Text);
71 private static void MergeMods(ContentPackage[] mods,
string resultName)
73 ModProject resultProject =
new ModProject
78 string targetDir = $
"{ContentPackage.LocalModsDir}/{resultName}";
79 Directory.CreateDirectory(targetDir);
81 foreach (var mod
in mods)
83 foreach (var file
in Directory.GetFiles(mod.Dir,
"*", System.IO.SearchOption.AllDirectories)
84 .Select(f => f.CleanUpPathCrossPlatform(correctFilenameCase:
false)))
86 if (Path.GetFileName(file).Equals(ContentPackage.FileListFileName, StringComparison.OrdinalIgnoreCase)) {
continue; }
88 string targetFilePath = file[mod.Dir.Length..];
89 if (targetFilePath.StartsWith(
"/") || targetFilePath.StartsWith(
"\\"))
91 targetFilePath = targetFilePath[1..];
94 targetFilePath = Path.Combine(targetDir, targetFilePath).CleanUpPathCrossPlatform(correctFilenameCase:
false);
97 Directory.CreateDirectory(Path.GetDirectoryName(targetFilePath)!);
98 File.Copy(file, targetFilePath, overwrite:
true);
100 var oldFileInProject = resultProject.Files.FirstOrDefault(f
101 => f.Path.Equals(targetFilePath, StringComparison.OrdinalIgnoreCase));
102 if (oldFileInProject !=
null)
104 resultProject.RemoveFile(oldFileInProject);
107 var fileInMod = mod.Files.Find(f => f.Path == file);
108 if (fileInMod !=
null)
110 var newFileInProject = ModProject.File.FromPath(targetFilePath, fileInMod.GetType());
111 resultProject.AddFile(newFileInProject);
115 resultProject.Save(Path.Combine(targetDir, ContentPackage.FileListFileName));
117 foreach (var mod
in mods)
119 Directory.Delete(mod.Dir);
121 (SettingsMenu.Instance!.WorkshopMenu as
MutableWorkshopMenu)!.PopulateInstalledModLists(forceRefreshEnabled:
true, refreshDisabled:
true);
124 private static void ErrorIfNonLocal(ContentPackage[] mods)
126 var nonLocal = mods.Where(m => !ContentPackageManager.LocalPackages.Contains(m)).ToArray();
129 throw new Exception($
"{string.Join(",
", nonLocal.Select(m => m.Name))} are not local mods");