Client LuaCsForBarotrauma
BulkDownloader.cs
1 #nullable enable
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Threading.Tasks;
8 using Microsoft.Xna.Framework;
9 
10 namespace Barotrauma.Steam
11 {
12  public static class BulkDownloader
13  {
14  private static void CloseAllMessageBoxes()
15  {
16  GUIMessageBox.MessageBoxes.ForEachMod(b =>
17  {
18  if (b is GUIMessageBox m) { m.Close(); }
19  else { GUIMessageBox.MessageBoxes.Remove(b); }
20  });
21  }
22 
23  public static void PrepareUpdates()
24  {
25  CloseAllMessageBoxes();
26  GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("DeterminingRequiredModUpdates"),
27  buttons: Array.Empty<LocalizedString>());
28  TaskPool.Add(
29  "BulkDownloader.PrepareUpdates > GetItemsThatNeedUpdating",
30  GetItemsThatNeedUpdating(),
31  t =>
32  {
33  msgBox.Close();
34  if (!t.TryGetResult(out IReadOnlyList<Steamworks.Ugc.Item>? items)) { return; }
35 
36  InitiateDownloads(items);
37  });
38  }
39 
40  internal static void SubscribeToServerMods(IEnumerable<UInt64> missingIds, ConnectCommand rejoinCommand)
41  {
42  CloseAllMessageBoxes();
43  GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("PreparingWorkshopDownloads"),
44  buttons: Array.Empty<LocalizedString>());
45  TaskPool.Add(
46  "BulkDownloader.SubscribeToServerMods > GetItems",
47  Task.WhenAll(missingIds.Select(SteamManager.Workshop.GetItem)),
48  t =>
49  {
50  msgBox.Close();
51  if (!t.TryGetResult(out Option<Steamworks.Ugc.Item>[]? itemOptions)) { return; }
52 
53  List<Steamworks.Ugc.Item> itemsToDownload = new List<Steamworks.Ugc.Item>();
54  foreach (Option<Steamworks.Ugc.Item> itemOption in itemOptions)
55  {
56  if (itemOption.TryUnwrap(out var item))
57  {
58  itemsToDownload.Add(item);
59  }
60  }
61 
62  itemsToDownload.ForEach(it => it.Subscribe());
63  InitiateDownloads(itemsToDownload, onComplete: () =>
64  {
65  ContentPackageManager.UpdateContentPackageList();
66  GameMain.Instance.ConnectCommand = Option<ConnectCommand>.Some(rejoinCommand);
67  });
68  });
69  }
70 
71  public static async Task<IReadOnlyList<Steamworks.Ugc.Item>> GetItemsThatNeedUpdating()
72  {
73  var determiningTasks = ContentPackageManager.WorkshopPackages.Select(async p => (p, await p.IsUpToDate()));
74  (ContentPackage Package, bool IsUpToDate)[] outOfDatePackages = await Task.WhenAll(determiningTasks);
75 
76  return (await Task.WhenAll(outOfDatePackages.Where(p => !p.IsUpToDate)
77  .Select(p => p.Package.UgcId)
78  .NotNone()
79  .OfType<SteamWorkshopId>()
80  .Select(async id => await SteamManager.Workshop.GetItem(id.Value))))
81  .NotNone().ToArray();
82  }
83 
84  public static void InitiateDownloads(IReadOnlyList<Steamworks.Ugc.Item> itemsToDownload, Action? onComplete = null)
85  {
86  var msgBox = new GUIMessageBox(TextManager.Get("WorkshopItemDownloading"), "", relativeSize: (0.5f, 0.6f),
87  buttons: new LocalizedString[] { TextManager.Get("Cancel") });
88  msgBox.Buttons[0].OnClicked = msgBox.Close;
89  var modsList = new GUIListBox(new RectTransform((1.0f, 0.8f), msgBox.Content.RectTransform))
90  {
91  HoverCursor = CursorState.Default
92  };
93  foreach (var item in itemsToDownload)
94  {
95  var itemFrame = new GUIFrame(new RectTransform((1.0f, 0.08f), modsList.Content.RectTransform),
96  style: null)
97  {
98  CanBeFocused = false
99  };
100  var itemTitle = new GUITextBlock(new RectTransform(Vector2.One, itemFrame.RectTransform),
101  text: item.Title ?? "");
102  var itemDownloadProgress
103  = new GUIProgressBar(new RectTransform((0.5f, 0.75f),
104  itemFrame.RectTransform, Anchor.CenterRight), 0.0f)
105  {
106  Color = GUIStyle.Green
107  };
108  var textShadow = new GUITextBlock(new RectTransform(Vector2.One, itemDownloadProgress.RectTransform) { AbsoluteOffset = new Point(GUI.IntScale(3)) }, "",
109  textColor: Color.Black, textAlignment: Alignment.Center);
110  var text = new GUITextBlock(new RectTransform(Vector2.One, itemDownloadProgress.RectTransform), "",
111  textAlignment: Alignment.Center);
112  var itemDownloadProgressUpdater = new GUICustomComponent(
113  new RectTransform(Vector2.Zero, msgBox.Content.RectTransform),
114  onUpdate: (f, component) =>
115  {
116  float progress = 0.0f;
117  if (item.IsDownloading)
118  {
119  progress = item.DownloadAmount;
120  text.Text = textShadow.Text = TextManager.GetWithVariable(
121  "PublishPopupDownload",
122  "[percentage]",
123  ((int)MathF.Round(item.DownloadAmount * 100)).ToString());
124  }
125  else if (itemDownloadProgress.BarSize > 0.0f)
126  {
127  if (!item.IsInstalled && !SteamManager.Workshop.CanBeInstalled(item.Id))
128  {
129  itemDownloadProgress.Color = GUIStyle.Red;
130  text.Text = textShadow.Text = TextManager.Get("workshopiteminstallfailed");
131  }
132  else
133  {
134  text.Text = textShadow.Text = TextManager.Get(item.IsInstalled ? "workshopiteminstalled" : "PublishPopupInstall");
135  }
136  progress = 1.0f;
137  }
138 
139  itemDownloadProgress.BarSize = Math.Max(itemDownloadProgress.BarSize,
140  MathHelper.Lerp(itemDownloadProgress.BarSize, progress, 0.1f));
141  });
142  }
143  TaskPool.Add("DownloadItems", DownloadItems(itemsToDownload, msgBox), _ =>
144  {
145  if (GUIMessageBox.MessageBoxes.Contains(msgBox))
146  {
147  onComplete?.Invoke();
148  }
149  msgBox.Close();
150  ContentPackageManager.WorkshopPackages.Refresh();
151  ContentPackageManager.EnabledPackages.RefreshUpdatedMods();
152  if (SettingsMenu.Instance?.WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu)
153  {
154  mutableWorkshopMenu.PopulateInstalledModLists(forceRefreshEnabled: true);
155  }
156  GameMain.MainMenuScreen.ResetModUpdateButton();
157  });
158  }
159 
160  private static async Task DownloadItems(IReadOnlyList<Steamworks.Ugc.Item> itemsToDownload, GUIMessageBox msgBox)
161  {
162  foreach (var item in itemsToDownload)
163  {
164  DebugConsole.Log($"Reinstalling {item.Title}...");
165  await SteamManager.Workshop.Reinstall(item);
166  DebugConsole.Log($"Finished installing {item.Title}...");
167  if (!GUIMessageBox.MessageBoxes.Contains(msgBox))
168  {
169  DebugConsole.Log($"Download prompt closed, interrupting {nameof(DownloadItems)}.");
170  break;
171  }
172  }
173  DebugConsole.Log($"{nameof(DownloadItems)} finished.");
174  }
175  }
176 }
CursorState
Definition: GUI.cs:40