Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/MultiPlayerCampaignSetupUI.cs
2025-06-17 16:38:11 +03:00

379 lines
16 KiB
C#

using Microsoft.Xna.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Barotrauma.Networking;
namespace Barotrauma
{
class MultiPlayerCampaignSetupUI : CampaignSetupUI
{
private GUIButton rollbackSaveButton;
private GUIButton deleteMpSaveButton;
private int prevInitialMoney;
private CampaignSettingElements campaignSettingElements;
public bool LoadGameMenuVisible => loadGameContainer is { Visible: true };
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, List<CampaignMode.SaveInfo> saveFiles = null)
: base(newGameContainer, loadGameContainer)
{
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: false)
{
Stretch = true,
RelativeSpacing = 0.025f
};
GUILayoutGroup nameSeedLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), verticalLayout.RectTransform), isHorizontal: false)
{
Stretch = true
};
GUILayoutGroup campaignSettingLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), verticalLayout.RectTransform), isHorizontal: false)
{
Stretch = true,
RelativeSpacing = 0.0f
};
// New game
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);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), saveLabel.RectTransform, Anchor.CenterRight), string.Empty)
{
textFilterFunction = ToolBox.RemoveInvalidFileNameChars
};
saveLabel.InheritTotalChildrenMinHeight();
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);
seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedLabel.RectTransform, Anchor.CenterRight), ToolBox.RandomSeed(8));
seedLabel.InheritTotalChildrenMinHeight();
nameSeedLayout.InheritTotalChildrenMinHeight();
campaignSettingElements = CreateCampaignSettingList(campaignSettingLayout, CampaignSettings.Empty, false);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f),
verticalLayout.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(30)) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
prevInitialMoney = CampaignSettings.DefaultInitialMoney;
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "", font: GUIStyle.SmallFont, textColor: GUIStyle.Green, textAlignment: Alignment.CenterRight)
{
TextGetter = () =>
{
int defaultInitialMoney = CampaignSettings.DefaultInitialMoney;
int initialMoney = defaultInitialMoney;
if (CampaignModePresets.TryGetAttribute(
nameof(CampaignSettings.StartingBalanceAmount).ToIdentifier(),
campaignSettingElements.StartingFunds.GetValue().ToIdentifier(),
out var attribute))
{
initialMoney = attribute.GetAttributeInt(defaultInitialMoney);
}
if (prevInitialMoney != initialMoney)
{
GameMain.NetLobbyScreen.RefreshEnabledElements();
prevInitialMoney = initialMoney;
}
if (GameMain.NetLobbyScreen.SelectedSub != null)
{
initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
}
initialMoney = Math.Max(initialMoney, 0);
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
}
};
verticalLayout.Recalculate();
CreateLoadMenu(saveFiles);
}
public bool StartGameClicked(GUIButton button, object userdata)
{
if (string.IsNullOrWhiteSpace(saveNameBox.Text))
{
saveNameBox.Flash(GUIStyle.Red, flashDuration: 5.0f);
saveNameBox.Pulsate(Vector2.One, Vector2.One * 1.2f, duration: 2.0f);
newGameContainer?.Flash(GUIStyle.Red, flashDuration: 0.5f);
return false;
}
SubmarineInfo selectedSub = null;
if (GameMain.NetLobbyScreen.SelectedSub == null) { return false; }
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
{
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("undefinedsubmarineselected"));
return false;
}
if (string.IsNullOrEmpty(selectedSub.MD5Hash.StringRepresentation))
{
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("nohashsubmarineselected"));
return false;
}
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveNameBox.Text);
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
CampaignSettings settings = campaignSettingElements.CreateSettings();
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
{
if (!hasRequiredContentPackages)
{
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = msgBox.Close;
msgBox.Buttons[0].OnClicked += (button, obj) =>
{
if (GUIMessageBox.MessageBoxes.Count == 0)
{
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
}
return true;
};
msgBox.Buttons[1].OnClicked = msgBox.Close;
}
if (selectedSub.HasTag(SubmarineTag.Shuttle))
{
var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
TextManager.Get("ShuttleWarning"),
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = (button, obj) =>
{
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = msgBox.Close;
return false;
}
}
else
{
StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text, settings);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
}
return true;
}
private IEnumerable<CoroutineStatus> WaitForCampaignSetup()
{
GUI.SetCursorWaiting();
var headerText = TextManager.Get("CampaignStartingPleaseWait");
var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new LocalizedString[] { TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
{
GameMain.NetLobbyScreen.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex);
GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex);
GUI.ClearCursorWait();
CoroutineManager.StopCoroutines("WaitForCampaignSetup");
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 20);
while (Screen.Selected != GameMain.GameScreen && DateTime.Now < timeOut)
{
msgBox.Header.Text = headerText + new string('.', (int)Timing.TotalTime % 3 + 1);
yield return CoroutineStatus.Running;
}
msgBox.Close();
GUI.ClearCursorWait();
yield return CoroutineStatus.Success;
}
public override void CreateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
{
prevSaveFiles?.Clear();
prevSaveFiles = null;
loadGameContainer.ClearChildren();
if (saveFiles == null)
{
saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer);
}
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.85f), loadGameContainer.RectTransform), childAnchor: Anchor.TopCenter)
{
Stretch = true,
RelativeSpacing = 0.03f
};
CreateSaveFilteringHeader(leftColumn);
saveList = new GUIListBox(new RectTransform(Vector2.One, leftColumn.RectTransform))
{
PlaySoundOnSelect = true,
OnSelected = SelectSaveFile
};
foreach (CampaignMode.SaveInfo saveInfo in saveFiles)
{
CreateSaveElement(saveInfo);
}
SortSaveList();
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
{
OnClicked = (btn, obj) =>
{
if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
if (saveInfo.RespawnMode != RespawnMode.None && saveInfo.RespawnMode != GameMain.NetworkMember?.ServerSettings?.RespawnMode)
{
var msgBox = new GUIMessageBox(TextManager.Get("Warning"),
TextManager.GetWithVariables("RespawnModeMismatch",
("[currentrespawnmode]", TextManager.Get($"respawnmode.{GameMain.NetworkMember?.ServerSettings?.RespawnMode}")),
("[savedrespawnmode]", TextManager.Get($"respawnmode.{saveInfo.RespawnMode}"))),
new LocalizedString[] { TextManager.Get("RespawnModeMismatch.GoBack"), TextManager.Get("RespawnModeMismatch.LoadAnyway") });
msgBox.Buttons[0].OnClicked = (button, obj) =>
{
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = (button, obj) =>
{
msgBox.Close();
LoadSaveGame();
return true;
};
return false;
}
LoadSaveGame();
return true;
void LoadSaveGame()
{
LoadGame?.Invoke(saveInfo.FilePath, backupIndex: Option.None);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
}
},
Enabled = false
};
GUILayoutGroup leftButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.15f), loadGameContainer.RectTransform, Anchor.BottomLeft))
{
RelativeSpacing = 0.05f,
Stretch = true
};
rollbackSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform), TextManager.Get("rollbackbutton"), style: "GUIButtonSmallFreeScale")
{
Visible = false,
ToolTip = TextManager.Get("backuptooltip"),
OnClicked = ViewBackupSaveMenu
};
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform),
TextManager.Get("Delete"), style: "GUIButtonSmallFreeScale")
{
OnClicked = DeleteSave,
Visible = false
};
}
private bool ViewBackupSaveMenu(GUIButton button, object obj)
{
if (obj is not CampaignMode.SaveInfo saveInfo) { return false; }
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
if (GameMain.Client.IsServerOwner)
{
CreateBackupMenu(SaveUtil.GetIndexData(saveInfo.FilePath), index =>
{
LoadGame(saveInfo.FilePath, backupIndex: Option.Some(index.Index));
});
}
else
{
RequestBackupIndexData(saveInfo.FilePath);
}
return true;
}
private const string PleaseWaitUserData = "PleaseWaitPopup";
private void RequestBackupIndexData(string savePath)
{
if (GameMain.Client == null) { return; }
GUI.SetCursorWaiting();
var msgBox = new GUIMessageBox(TextManager.Get("CampaignStartingPleaseWait"), TextManager.Get("CampaignStarting"), new[] { TextManager.Get("Cancel") })
{
UserData = PleaseWaitUserData
};
msgBox.Buttons[0].OnClicked = (btn, obj) =>
{
GUI.ClearCursorWait();
return true;
};
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.REQUEST_BACKUP_INDICES);
msg.WriteString(savePath);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
public void OnBackupIndicesReceived(IReadMessage message)
{
GUI.ClearCursorWait();
foreach (GUIComponent component in GUIMessageBox.MessageBoxes.Where(static mb => mb.UserData is PleaseWaitUserData).ToArray())
{
if (component is GUIMessageBox msgBox)
{
msgBox.Close();
}
}
string path = message.ReadString();
var indexData = INetSerializableStruct.Read<NetCollection<SaveUtil.BackupIndexData>>(message);
CreateBackupMenu(indexData, selectedIndex =>
{
LoadGame?.Invoke(path, backupIndex: Option.Some(selectedIndex.Index));
});
}
private bool SelectSaveFile(GUIComponent component, object obj)
{
if (obj is not CampaignMode.SaveInfo saveInfo) { return true; }
string fileName = saveInfo.FilePath;
loadGameButton.Enabled = true;
rollbackSaveButton.Visible = true;
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
rollbackSaveButton.Enabled = deleteMpSaveButton.Enabled = GameMain.GameSession?.DataPath.LoadPath != fileName;
if (deleteMpSaveButton.Visible)
{
deleteMpSaveButton.UserData = saveInfo;
}
if (rollbackSaveButton.Visible)
{
rollbackSaveButton.UserData = saveInfo;
}
return true;
}
}
}