Client LuaCsForBarotrauma
ModListPreset.cs
1 #nullable enable
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Linq;
6 using System.Xml.Linq;
7 using Barotrauma.IO;
9 using Barotrauma.Steam;
10 using Microsoft.Xna.Framework;
11 
12 namespace Barotrauma
13 {
14  readonly struct ModListPreset
15  {
16  public const string SavePath = "ModLists";
17 
18  public enum ModType
19  {
20  Vanilla,
21  Local,
22  Workshop
23  }
24 
25  public readonly string Name;
26  public readonly CorePackage CorePackage;
27  public readonly ImmutableArray<RegularPackage> RegularPackages;
28 
29  public ModListPreset(XDocument doc)
30  {
31  Name = doc.Root!.GetAttributeString("name", "");
32 
33  CorePackage corePackage = ContentPackageManager.VanillaCorePackage!;
34  List<RegularPackage> regularPackages = new List<RegularPackage>();
35  void addPkg(ContentPackage pkg)
36  {
37  if (pkg is CorePackage core) { corePackage = core; }
38  else if (pkg is RegularPackage reg) { regularPackages.Add(reg); }
39  }
40 
41  foreach (var element in doc.Root!.Elements())
42  {
43  ModType modType = Enum.TryParse<ModType>(element.Name.LocalName, ignoreCase: true, out var mt) ? mt : ModType.Local;
44 
45  switch (modType)
46  {
47  case ModType.Vanilla:
48  CorePackage = ContentPackageManager.VanillaCorePackage!;
49  break;
50  case ModType.Workshop:
51  {
52  var id = element.GetAttributeUInt64("id", 0);
53  if (id == 0) { continue; }
54  var pkg = ContentPackageManager.WorkshopPackages.FirstOrDefault(p =>
55  p.TryExtractSteamWorkshopId(out var workshopId) && workshopId.Value == id);
56  if (pkg != null) { addPkg(pkg); }
57  }
58  break;
59  case ModType.Local:
60  {
61  var name = element.GetAttributeString("name", "");
62  if (name.IsNullOrEmpty()) { continue; }
63  var pkg = ContentPackageManager.LocalPackages.FirstOrDefault(p => p.NameMatches(name));
64  if (pkg != null) { addPkg(pkg); }
65  }
66  break;
67  }
68  }
69 
70  CorePackage = corePackage;
71  RegularPackages = regularPackages.ToImmutableArray();
72  }
73 
74  public ModListPreset(string name, CorePackage corePackage, IReadOnlyList<RegularPackage> regularPackages)
75  {
76  Name = name;
77  CorePackage = corePackage;
78  RegularPackages = regularPackages.ToImmutableArray();
79  }
80 
82  {
83  LocalizedString retVal = $"‖color:gui.orange‖{Name}‖end‖" //TODO: we need a RichString builder
84  + "\n " + TextManager.AddPunctuation(':', TextManager.Get("CorePackage"))
85  + "\n - " + CorePackage.Name;
86  if (RegularPackages.Any())
87  {
88  retVal += "\n " + TextManager.AddPunctuation(':', TextManager.Get("RegularPackages"))
89  + "\n - "
90  + LocalizedString.Join("\n - ", RegularPackages.Select(p => (LocalizedString)p.Name));
91  }
92 
93  return RichString.Rich(retVal);
94  }
95 
96  public void Save()
97  {
98  XDocument newDoc = new XDocument();
99  XElement newRoot = new XElement("mods", new XAttribute("name", Name));
100  newDoc.Add(newRoot);
101 
102  ModType determineType(ContentPackage pkg)
103  {
104  if (pkg == ContentPackageManager.VanillaCorePackage) { return ModType.Vanilla; }
105  if (ContentPackageManager.WorkshopPackages.Contains(pkg)) { return ModType.Workshop; }
106  return ModType.Local;
107  }
108  void writePkgElem(ContentPackage pkg)
109  {
110  var pkgType = determineType(pkg);
111  var pkgElem = new XElement(pkgType.ToString());
112  switch (pkgType)
113  {
114  case ModType.Workshop:
115  pkgElem.SetAttributeValue("name", pkg.Name);
116  if (pkg.UgcId.TryUnwrap(out var ugcId))
117  {
118  pkgElem.SetAttributeValue("id", ugcId.ToString());
119  }
120  break;
121  case ModType.Local:
122  pkgElem.SetAttributeValue("name", pkg.Name);
123  break;
124  }
125  newRoot.Add(pkgElem);
126  }
127  writePkgElem(CorePackage);
128  RegularPackages.ForEach(writePkgElem);
129 
130  if (!Directory.Exists(SavePath)) { Directory.CreateDirectory(SavePath); }
131  newDoc.SaveSafe(Path.Combine(SavePath, ToolBox.RemoveInvalidFileNameChars($"{Name}.xml")));
132  }
133  }
134 }
135 
136 namespace Barotrauma.Steam
137 {
138  sealed partial class MutableWorkshopMenu : WorkshopMenu
139  {
140  private bool OpenLoadPreset(GUIButton _, object __)
141  {
142  OpenLoadPreset();
143  return false;
144  }
145 
146  private void OpenLoadPreset()
147  {
148  var msgBox = new GUIMessageBox(
149  TextManager.Get("LoadModListPresetHeader"),
150  "",
151  buttons: new [] { TextManager.Get("Load"), TextManager.Get("Cancel") },
152  relativeSize: (0.4f, 0.6f));
153 
154  var presetListBox = new GUIListBox(new RectTransform((1.0f, 0.7f), msgBox.Content.RectTransform));
155 
156  (string Path, XDocument? Doc) tryLoadXml(string path)
157  => (path, XMLExtensions.TryLoadXml(path));
158 
159  var presets = Directory.Exists(ModListPreset.SavePath)
160  ? Directory.GetFiles(ModListPreset.SavePath)
161  .Select(tryLoadXml)
162  .Where(d => d.Doc != null)
163  .ToArray()
164  : Array.Empty<(string Path, XDocument? Doc)>();
165 
166  foreach (var doc in presets)
167  {
168  ModListPreset preset = new ModListPreset(doc.Doc!);
169  var presetFrame = new GUIFrame(new RectTransform((1.0f, 0.09f), presetListBox.Content.RectTransform),
170  style: "ListBoxElement")
171  {
172  UserData = preset,
173  ToolTip = preset.GetTooltip()
174  };
175  new GUITextBlock(new RectTransform(Vector2.One, presetFrame.RectTransform), preset.Name)
176  {
177  CanBeFocused = false
178  };
179  var deleteBtn
180  = new GUIButton(new RectTransform((0.2f, 1.0f), presetFrame.RectTransform, Anchor.CenterRight),
181  TextManager.Get("Delete"), style: "GUIButtonSmall")
182  {
183  OnClicked = (button, o) =>
184  {
185  File.Delete(doc.Path);
186  presetListBox.Content.RemoveChild(presetFrame);
187  return false;
188  }
189  };
190  }
191 
192  msgBox.Buttons[0].OnClicked = (button, o) =>
193  {
194  if (presetListBox.SelectedData is ModListPreset preset)
195  {
196  var allChildren = enabledRegularModsList.Content.Children
197  .Concat(disabledRegularModsList.Content.Children)
198  .ToArray();
199  enabledRegularModsList.ClearChildren();
200  disabledRegularModsList.ClearChildren();
201  var toEnable =
202  allChildren.Where(c => c.UserData is RegularPackage p
203  && preset.RegularPackages.Contains(p))
204  .OrderBy(c => c.UserData is RegularPackage p ? preset.RegularPackages.IndexOf(p) : int.MaxValue)
205  .ToArray();
206  var toDisable = allChildren.Where(c => !toEnable.Contains(c)).ToArray();
207  toEnable.ForEach(c => c.RectTransform.Parent = enabledRegularModsList.Content.RectTransform);
208  toDisable.ForEach(c => c.RectTransform.Parent = disabledRegularModsList.Content.RectTransform);
209 
210  enabledCoreDropdown.SelectItem(preset.CorePackage);
211  }
212  msgBox.Close();
213  return false;
214  };
215  msgBox.Buttons[1].OnClicked = msgBox.Close;
216  }
217 
218  private bool OpenSavePreset(GUIButton _, object __)
219  {
220  OpenSavePreset();
221  return false;
222  }
223 
224  private void OpenSavePreset()
225  {
226  var msgBox = new GUIMessageBox(
227  TextManager.Get("SaveModListPresetHeader"),
228  "",
229  buttons: new [] { TextManager.Get("Save"), TextManager.Get("Cancel") },
230  relativeSize: (0.4f, 0.2f));
231 
232  var nameBox = new GUITextBox(new RectTransform((1.0f, 0.3f), msgBox.Content.RectTransform), "");
233 
234  msgBox.Buttons[0].OnClicked = (button, o) =>
235  {
236  if (nameBox.Text.IsNullOrEmpty())
237  {
238  nameBox.Flash(GUIStyle.Red);
239  return false;
240  }
241 
242  if (enabledCoreDropdown.SelectedData is CorePackage corePackage)
243  {
244  ModListPreset preset = new ModListPreset(nameBox.Text,
245  corePackage,
246  enabledRegularModsList.Content.Children
247  .Select(c => c.UserData)
248  .OfType<RegularPackage>().ToArray());
249  preset.Save();
250  }
251  msgBox.Close();
252  return false;
253  };
254  msgBox.Buttons[1].OnClicked = msgBox.Close;
255  }
256  }
257 }
readonly Option< ContentPackageId > UgcId
RectTransform RectTransform
IEnumerable< GUIComponent > Children
Definition: GUIComponent.cs:29
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
Definition: GUIListBox.cs:33
override void ClearChildren()
Definition: GUIListBox.cs:1243
static LocalizedString Join(string separator, params LocalizedString[] subStrs)
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
Definition: RichString.cs:67
ModListPreset(string name, CorePackage corePackage, IReadOnlyList< RegularPackage > regularPackages)
ModListPreset(XDocument doc)
readonly CorePackage CorePackage
readonly string Name
readonly ImmutableArray< RegularPackage > RegularPackages