Client LuaCsForBarotrauma
MultiPlayerCampaignSetupUI.cs
1 using Microsoft.Xna.Framework;
2 using System;
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Globalization;
6 using System.Linq;
8 
9 namespace Barotrauma
10 {
12  {
13  private GUIButton rollbackSaveButton;
14  private GUIButton deleteMpSaveButton;
15 
16  private int prevInitialMoney;
17 
18  private CampaignSettingElements campaignSettingElements;
19 
20  public bool LoadGameMenuVisible => loadGameContainer is { Visible: true };
21 
22  public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, List<CampaignMode.SaveInfo> saveFiles = null)
23  : base(newGameContainer, loadGameContainer)
24  {
25  var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: false)
26  {
27  Stretch = true,
28  RelativeSpacing = 0.025f
29  };
30 
31  GUILayoutGroup nameSeedLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), verticalLayout.RectTransform), isHorizontal: false)
32  {
33  Stretch = true
34  };
35 
36  GUILayoutGroup campaignSettingLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), verticalLayout.RectTransform), isHorizontal: false)
37  {
38  Stretch = true,
39  RelativeSpacing = 0.0f
40  };
41 
42  // New game
43  var saveLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, GUI.IntScale(24)) }, TextManager.Get("SaveName"), textAlignment: Alignment.CenterLeft);
44  saveNameBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), saveLabel.RectTransform, Anchor.CenterRight), string.Empty)
45  {
46  textFilterFunction = ToolBox.RemoveInvalidFileNameChars
47  };
49 
50  var seedLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, GUI.IntScale(24)) }, TextManager.Get("MapSeed"), textAlignment: Alignment.CenterLeft);
51  seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedLabel.RectTransform, Anchor.CenterRight), ToolBox.RandomSeed(8));
52  seedLabel.InheritTotalChildrenMinHeight();
53 
54  nameSeedLayout.InheritTotalChildrenMinHeight();
55 
56  campaignSettingElements = CreateCampaignSettingList(campaignSettingLayout, CampaignSettings.Empty, false);
57 
58  var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f),
59  verticalLayout.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(30)) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
60 
61  prevInitialMoney = CampaignSettings.DefaultInitialMoney;
62  InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "", font: GUIStyle.SmallFont, textColor: GUIStyle.Green, textAlignment: Alignment.CenterRight)
63  {
64  TextGetter = () =>
65  {
66  int defaultInitialMoney = CampaignSettings.DefaultInitialMoney;
67  int initialMoney = defaultInitialMoney;
68  if (CampaignModePresets.TryGetAttribute(
69  nameof(CampaignSettings.StartingBalanceAmount).ToIdentifier(),
70  campaignSettingElements.StartingFunds.GetValue().ToIdentifier(),
71  out var attribute))
72  {
73  initialMoney = attribute.GetAttributeInt(defaultInitialMoney);
74  }
75  if (prevInitialMoney != initialMoney)
76  {
78  prevInitialMoney = initialMoney;
79  }
81  {
82  initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
83  }
84  initialMoney = Math.Max(initialMoney, 0);
85 
86  return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
87  }
88  };
89 
90  verticalLayout.Recalculate();
91 
92  CreateLoadMenu(saveFiles);
93  }
94 
95  public bool StartGameClicked(GUIButton button, object userdata)
96  {
97  if (string.IsNullOrWhiteSpace(saveNameBox.Text))
98  {
99  saveNameBox.Flash(GUIStyle.Red, flashDuration: 5.0f);
100  saveNameBox.Pulsate(Vector2.One, Vector2.One * 1.2f, duration: 2.0f);
101  newGameContainer?.Flash(GUIStyle.Red, flashDuration: 0.5f);
102  return false;
103  }
104 
105  SubmarineInfo selectedSub = null;
106 
107  if (GameMain.NetLobbyScreen.SelectedSub == null) { return false; }
108  selectedSub = GameMain.NetLobbyScreen.SelectedSub;
109 
110  if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
111  {
112  new GUIMessageBox(TextManager.Get("error"), TextManager.Get("undefinedsubmarineselected"));
113  return false;
114  }
115 
116  if (string.IsNullOrEmpty(selectedSub.MD5Hash.StringRepresentation))
117  {
118  new GUIMessageBox(TextManager.Get("error"), TextManager.Get("nohashsubmarineselected"));
119  return false;
120  }
121 
122  string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveNameBox.Text);
123  bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
124 
125  CampaignSettings settings = campaignSettingElements.CreateSettings();
126 
127  if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
128  {
129  if (!hasRequiredContentPackages)
130  {
131  var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
132  TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
133  new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
134 
135  msgBox.Buttons[0].OnClicked = msgBox.Close;
136  msgBox.Buttons[0].OnClicked += (button, obj) =>
137  {
138  if (GUIMessageBox.MessageBoxes.Count == 0)
139  {
140  StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
141  CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
142  }
143  return true;
144  };
145 
146  msgBox.Buttons[1].OnClicked = msgBox.Close;
147  }
148 
149  if (selectedSub.HasTag(SubmarineTag.Shuttle))
150  {
151  var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
152  TextManager.Get("ShuttleWarning"),
153  new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
154 
155  msgBox.Buttons[0].OnClicked = (button, obj) =>
156  {
157  StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
158  CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
159  return true;
160  };
161  msgBox.Buttons[0].OnClicked += msgBox.Close;
162 
163  msgBox.Buttons[1].OnClicked = msgBox.Close;
164  return false;
165  }
166  }
167  else
168  {
169  StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
170  CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
171  }
172 
173  return true;
174  }
175 
176  private IEnumerable<CoroutineStatus> WaitForCampaignSetup()
177  {
178  GUI.SetCursorWaiting();
179  var headerText = TextManager.Get("CampaignStartingPleaseWait");
180  var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new LocalizedString[] { TextManager.Get("Cancel") });
181 
182  msgBox.Buttons[0].OnClicked = (btn, userdata) =>
183  {
186  GUI.ClearCursorWait();
187  CoroutineManager.StopCoroutines("WaitForCampaignSetup");
188  return true;
189  };
190  msgBox.Buttons[0].OnClicked += msgBox.Close;
191 
192  DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 20);
193  while (Screen.Selected != GameMain.GameScreen && DateTime.Now < timeOut)
194  {
195  msgBox.Header.Text = headerText + new string('.', (int)Timing.TotalTime % 3 + 1);
196  yield return CoroutineStatus.Running;
197  }
198  msgBox.Close();
199  GUI.ClearCursorWait();
200  yield return CoroutineStatus.Success;
201  }
202 
203  public override void CreateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
204  {
205  prevSaveFiles?.Clear();
206  prevSaveFiles = null;
207  loadGameContainer.ClearChildren();
208 
209  if (saveFiles == null)
210  {
211  saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
212  }
213 
214  var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.85f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
215  {
216  Stretch = true,
217  RelativeSpacing = 0.03f
218  };
219 
220  saveList = new GUIListBox(new RectTransform(Vector2.One, leftColumn.RectTransform))
221  {
222  PlaySoundOnSelect = true,
223  OnSelected = SelectSaveFile
224  };
225 
226  foreach (CampaignMode.SaveInfo saveInfo in saveFiles)
227  {
228  CreateSaveElement(saveInfo);
229  }
230 
231  SortSaveList();
232 
233  loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
234  {
235  OnClicked = (btn, obj) =>
236  {
237  if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
238  if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
239  LoadGame?.Invoke(saveInfo.FilePath, backupIndex: Option.None);
240 
241  CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
242  return true;
243  },
244  Enabled = false
245  };
246 
247  GUILayoutGroup leftButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.15f), loadGameContainer.RectTransform, Anchor.BottomLeft))
248  {
249  RelativeSpacing = 0.05f,
250  Stretch = true
251  };
252 
253  rollbackSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform), TextManager.Get("rollbackbutton"), style: "GUIButtonSmallFreeScale")
254  {
255  Visible = false,
256  ToolTip = TextManager.Get("backuptooltip"),
257  OnClicked = ViewBackupSaveMenu
258  };
259  deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform),
260  TextManager.Get("Delete"), style: "GUIButtonSmallFreeScale")
261  {
262  OnClicked = DeleteSave,
263  Visible = false
264  };
265  }
266 
267  private bool ViewBackupSaveMenu(GUIButton button, object obj)
268  {
269  if (obj is not CampaignMode.SaveInfo saveInfo) { return false; }
270  if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
271 
272  if (GameMain.Client.IsServerOwner)
273  {
274  CreateBackupMenu(SaveUtil.GetIndexData(saveInfo.FilePath), index =>
275  {
276  LoadGame(saveInfo.FilePath, backupIndex: Option.Some(index.Index));
277  });
278  }
279  else
280  {
281  RequestBackupIndexData(saveInfo.FilePath);
282  }
283  return true;
284  }
285 
286  private const string PleaseWaitUserData = "PleaseWaitPopup";
287 
288  private void RequestBackupIndexData(string savePath)
289  {
290  if (GameMain.Client == null) { return; }
291 
292  GUI.SetCursorWaiting();
293  var msgBox = new GUIMessageBox(TextManager.Get("CampaignStartingPleaseWait"), TextManager.Get("CampaignStarting"), new[] { TextManager.Get("Cancel") })
294  {
295  UserData = PleaseWaitUserData
296  };
297  msgBox.Buttons[0].OnClicked = (btn, obj) =>
298  {
299  GUI.ClearCursorWait();
300  return true;
301  };
302 
303 
304  IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.REQUEST_BACKUP_INDICES);
305  msg.WriteString(savePath);
306  GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
307  }
308 
310  {
311  GUI.ClearCursorWait();
312 
313  foreach (GUIComponent component in GUIMessageBox.MessageBoxes.Where(static mb => mb.UserData is PleaseWaitUserData).ToArray())
314  {
315  if (component is GUIMessageBox msgBox)
316  {
317  msgBox.Close();
318  }
319  }
320 
321  string path = message.ReadString();
322  var indexData = INetSerializableStruct.Read<NetCollection<SaveUtil.BackupIndexData>>(message);
323  CreateBackupMenu(indexData, selectedIndex =>
324  {
325  LoadGame?.Invoke(path, backupIndex: Option.Some(selectedIndex.Index));
326  });
327  }
328 
329  private bool SelectSaveFile(GUIComponent component, object obj)
330  {
331  if (obj is not CampaignMode.SaveInfo saveInfo) { return true; }
332  string fileName = saveInfo.FilePath;
333 
334  loadGameButton.Enabled = true;
335  rollbackSaveButton.Visible = true;
336  deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
337  rollbackSaveButton.Enabled = deleteMpSaveButton.Enabled = GameMain.GameSession?.DataPath.LoadPath != fileName;
338  if (deleteMpSaveButton.Visible)
339  {
340  deleteMpSaveButton.UserData = saveInfo;
341  }
342 
343  if (rollbackSaveButton.Visible)
344  {
345  rollbackSaveButton.UserData = saveInfo;
346  }
347  return true;
348  }
349  }
350 }
readonly GUIComponent newGameContainer
GUIComponent CreateSaveElement(CampaignMode.SaveInfo saveInfo)
Action< SubmarineInfo, string, string, CampaignSettings > StartNewGame
static CampaignSettingElements CreateCampaignSettingList(GUIComponent parent, CampaignSettings prevSettings, bool isSinglePlayer)
List< CampaignMode.SaveInfo > prevSaveFiles
void CreateBackupMenu(IEnumerable< SaveUtil.BackupIndexData > indexData, Action< SaveUtil.BackupIndexData > loadBackup)
bool DeleteSave(GUIButton button, object obj)
override bool Enabled
Definition: GUIButton.cs:27
virtual void Flash(Color? color=null, float flashDuration=1.5f, bool useRectangleFlash=false, bool useCircularFlash=false, Vector2? flashRectInflate=null)
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
void InheritTotalChildrenMinHeight()
Sets the minimum height of the transfrom to equal to the sum of the minimum heights of the children (...
RectTransform RectTransform
static readonly List< GUIComponent > MessageBoxes
override void Flash(Color? color=null, float flashDuration=1.5f, bool useRectangleFlash=false, bool useCircularFlash=false, Vector2? flashRectOffset=null)
Definition: GUITextBox.cs:411
static NetLobbyScreen NetLobbyScreen
Definition: GameMain.cs:55
readonly string StringRepresentation
Definition: Md5Hash.cs:32
bool StartGameClicked(GUIButton button, object userdata)
MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, List< CampaignMode.SaveInfo > saveFiles=null)
override void CreateLoadMenu(IEnumerable< CampaignMode.SaveInfo > saveFiles=null)
SettingValue< StartingBalanceAmountOption > StartingFunds