diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index 72eae2114..032ea9822 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -196,6 +196,7 @@ + diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs index 3c7dcea37..f114c7ddc 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs @@ -525,9 +525,19 @@ namespace Barotrauma if (children.Contains(child)) children.Remove(child); } - public GUIComponent FindChild(object userData) + public GUIComponent FindChild(object userData, bool recursive = false) { - return children.FirstOrDefault(c => c.userData == userData); + var matchingChild = children.FirstOrDefault(c => c.userData == userData); + if (recursive && matchingChild == null) + { + foreach (GUIComponent child in children) + { + matchingChild = child.FindChild(userData, recursive); + if (matchingChild != null) return matchingChild; + } + } + + return matchingChild; } public List FindChildren(object userData) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs index 9e0755058..77e91591c 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs @@ -20,6 +20,11 @@ namespace Barotrauma get { return MessageBoxes.Count == 0 ? null : MessageBoxes[0]; } } + public GUIFrame InnerFrame + { + get { return children[0] as GUIFrame; } + } + public string Text { get { return (children[0].children[1] as GUITextBlock).Text; } @@ -78,12 +83,15 @@ namespace Barotrauma MessageBoxes.Add(this); } - - - public bool Close(GUIButton button, object obj) + public void Close() { if (parent != null) parent.RemoveChild(this); if (MessageBoxes.Contains(this)) MessageBoxes.Remove(this); + } + + public bool Close(GUIButton button, object obj) + { + Close(); return true; } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs index d3b1feacb..50e992f4d 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs @@ -344,7 +344,7 @@ namespace Barotrauma public override void Save(XElement element) { - XElement modeElement = new XElement("gamemode"); + XElement modeElement = new XElement("SinglePlayerCampaign"); modeElement.Add(new XAttribute("money", Money)); diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs index b5ea938c3..c5d48a0a9 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs @@ -15,7 +15,7 @@ namespace Barotrauma { get { - SinglePlayerCampaign mode = (GameMode as SinglePlayerCampaign); + CampaignMode mode = (GameMode as CampaignMode); return (mode == null) ? null : mode.Map; } } @@ -168,32 +168,5 @@ namespace Barotrauma if (GameMode != null) GameMode.Draw(spriteBatch); if (infoFrame != null) infoFrame.Draw(spriteBatch); } - - public void Save(string filePath) - { - if (!(GameMode is CampaignMode)) - { - throw new NotSupportedException("GameSessions can only be saved when playing in a campaign mode."); - } - - XDocument doc = new XDocument( - new XElement("Gamesession")); - - var now = DateTime.Now; - doc.Root.Add(new XAttribute("savetime", now.ToShortTimeString() + ", " + now.ToShortDateString())); - doc.Root.Add(new XAttribute("submarine", submarine == null ? "" : submarine.Name)); - doc.Root.Add(new XAttribute("mapseed", Map.Seed)); - - ((CampaignMode)GameMode).Save(doc.Root); - - try - { - doc.Save(filePath); - } - catch - { - DebugConsole.ThrowError("Saving gamesession to \"" + filePath + "\" failed!"); - } - } } } diff --git a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs index 962692ab3..f90361ffc 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs @@ -1,9 +1,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; -using System.Collections.Generic; using System.Linq; -using System.Xml.Linq; namespace Barotrauma { @@ -68,6 +66,9 @@ namespace Barotrauma Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Vector2 offset = -currentLocation.MapPosition; + Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; + GameMain.Instance.GraphicsDevice.ScissorRectangle = rect; + iceTexture.DrawTiled(spriteBatch, new Vector2(rect.X, rect.Y), new Vector2(rect.Width, rect.Height), Vector2.Zero, Color.White * 0.8f); foreach (LocationConnection connection in connections) @@ -197,31 +198,8 @@ namespace Barotrauma GUI.DrawString(spriteBatch, pos, location.Name, Color.White, Color.Black * 0.8f, 3); } - } - public void Save(XElement element) - { - XElement mapElement = new XElement("map"); - - mapElement.Add(new XAttribute("currentlocation", CurrentLocationIndex)); - mapElement.Add(new XAttribute("seed", Seed)); - mapElement.Add(new XAttribute("size", size)); - - List discoveredLocations = new List(); - for (int i = 0; i < locations.Count; i++) - { - if (locations[i].Discovered) discoveredLocations.Add(i); - } - mapElement.Add(new XAttribute("discovered", string.Join(",", discoveredLocations))); - - List passedConnections = new List(); - for (int i = 0; i < connections.Count; i++) - { - if (connections[i].Passed) passedConnections.Add(i); - } - mapElement.Add(new XAttribute("passed", string.Join(",", passedConnections))); - - element.Add(mapElement); + GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; } } } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs b/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs index c4b080b92..3dbde1d8d 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs @@ -15,7 +15,7 @@ namespace Barotrauma if (value == allowSubVoting) return; allowSubVoting = value; GameMain.NetLobbyScreen.SubList.Enabled = value || GameMain.Server != null; - GameMain.NetLobbyScreen.InfoFrame.FindChild("subvotes").Visible = value; + GameMain.NetLobbyScreen.InfoFrame.FindChild("subvotes", true).Visible = value; if (GameMain.Server != null) { @@ -36,7 +36,7 @@ namespace Barotrauma if (value == allowModeVoting) return; allowModeVoting = value; GameMain.NetLobbyScreen.ModeList.Enabled = value || GameMain.Server != null; - GameMain.NetLobbyScreen.InfoFrame.FindChild("modevotes").Visible = value; + GameMain.NetLobbyScreen.InfoFrame.FindChild("modevotes", true).Visible = value; if (GameMain.Server != null) { UpdateVoteTexts(GameMain.Server.ConnectedClients, VoteType.Mode); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs new file mode 100644 index 000000000..9920cf052 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -0,0 +1,210 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Barotrauma +{ + class CampaignSetupUI + { + private GUIComponent newGameContainer, loadGameContainer; + + private GUIListBox subList; + private GUIListBox saveList; + + private GUITextBox saveNameBox, seedBox; + + public Action StartNewGame; + public Action LoadGame; + + private bool isMultiplayer; + + public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer) + { + this.isMultiplayer = isMultiplayer; + this.newGameContainer = newGameContainer; + this.loadGameContainer = loadGameContainer; + + new GUITextBlock(new Rectangle(0, 0, 0, 30), "Selected submarine:", null, null, Alignment.Left, "", newGameContainer); + subList = new GUIListBox(new Rectangle(0, 30, 230, newGameContainer.Rect.Height - 100), "", newGameContainer); + + UpdateSubList(); + + new GUITextBlock(new Rectangle((int)(subList.Rect.Width + 20), 0, 100, 20), + "Save name: ", "", Alignment.Left, Alignment.Left, newGameContainer); + + saveNameBox = new GUITextBox(new Rectangle((int)(subList.Rect.Width + 30), 30, 180, 20), + Alignment.TopLeft, "", newGameContainer); + + new GUITextBlock(new Rectangle((int)(subList.Rect.Width + 20), 60, 100, 20), + "Map Seed: ", "", Alignment.Left, Alignment.Left, newGameContainer); + + seedBox = new GUITextBox(new Rectangle((int)(subList.Rect.Width + 30), 90, 180, 20), + Alignment.TopLeft, "", newGameContainer); + seedBox.Text = ToolBox.RandomSeed(8); + + var startButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, "", newGameContainer); + startButton.OnClicked = (GUIButton btn, object userData) => + { + if (string.IsNullOrWhiteSpace(saveNameBox.Text)) + { + saveNameBox.Flash(Color.Red); + return false; + } + + Submarine selectedSub = subList.SelectedData as Submarine; + if (selectedSub != null && selectedSub.HasTag(SubmarineTag.Shuttle)) + { + var msgBox = new GUIMessageBox("Shuttle selected", + "Most shuttles are not adequately equipped to deal with the dangers of the Europan depths. " + + "Are you sure you want to choose a shuttle as your vessel?", + new string[] { "Yes", "No" }); + + msgBox.Buttons[0].OnClicked = (button, obj) => { StartNewGame?.Invoke(selectedSub, saveNameBox.Text, seedBox.Text); return true; }; + msgBox.Buttons[0].OnClicked += msgBox.Close; + + msgBox.Buttons[1].OnClicked = msgBox.Close; + return false; + } + + StartNewGame?.Invoke(selectedSub, saveNameBox.Text, seedBox.Text); + + return true; + }; + + UpdateLoadMenu(); + } + + public void CreateDefaultSaveName() + { + saveNameBox.Text = SaveUtil.CreateSavePath(); + } + + public void UpdateSubList() + { + var subsToShow = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)); + + subList.ClearChildren(); + + foreach (Submarine sub in subsToShow) + { + var textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + ToolBox.LimitString(sub.Name, GUI.Font, subList.Rect.Width - 65), "ListBoxElement", + Alignment.Left, Alignment.Left, subList) + { + Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f), + ToolTip = sub.Description, + UserData = sub + }; + + if (sub.HasTag(SubmarineTag.Shuttle)) + { + textBlock.TextColor = textBlock.TextColor * 0.85f; + + var shuttleText = new GUITextBlock(new Rectangle(0, 0, 0, 25), "Shuttle", "", Alignment.Left, Alignment.CenterY | Alignment.Right, textBlock, false, GUI.SmallFont); + shuttleText.TextColor = textBlock.TextColor * 0.8f; + shuttleText.ToolTip = textBlock.ToolTip; + } + } + if (Submarine.SavedSubmarines.Count > 0) subList.Select(Submarine.SavedSubmarines[0]); + } + + public void UpdateLoadMenu() + { + loadGameContainer.ClearChildren(); + + string[] saveFiles = SaveUtil.GetSaveFiles(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer); + + saveList = new GUIListBox(new Rectangle(0, 0, 200, loadGameContainer.Rect.Height - 80), Color.White, "", loadGameContainer); + saveList.OnSelected = SelectSaveFile; + + foreach (string saveFile in saveFiles) + { + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + Path.GetFileNameWithoutExtension(saveFile), + "ListBoxElement", + Alignment.Left, + Alignment.Left, + saveList); + textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); + textBlock.UserData = saveFile; + } + + var button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.Right | Alignment.Bottom, "", loadGameContainer); + button.OnClicked = (btn, obj) => { LoadGame?.Invoke(saveList.SelectedData as string); return true; }; + } + + private bool SelectSaveFile(GUIComponent component, object obj) + { + string fileName = (string)obj; + + XDocument doc = SaveUtil.LoadGameSessionDoc(fileName); + + if (doc == null) + { + DebugConsole.ThrowError("Error loading save file \"" + fileName + "\". The file may be corrupted."); + return false; + } + + RemoveSaveFrame(); + + string subName = ToolBox.GetAttributeString(doc.Root, "submarine", ""); + string saveTime = ToolBox.GetAttributeString(doc.Root, "savetime", "unknown"); + string mapseed = ToolBox.GetAttributeString(doc.Root, "mapseed", "unknown"); + + GUIFrame saveFileFrame = new GUIFrame(new Rectangle((int)(saveList.Rect.Width + 20), 0, 200, 230), Color.Black * 0.4f, "", loadGameContainer); + saveFileFrame.UserData = "savefileframe"; + saveFileFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); + + new GUITextBlock(new Rectangle(0, 0, 0, 20), Path.GetFileNameWithoutExtension(fileName), "", Alignment.TopLeft, Alignment.TopLeft, saveFileFrame, false, GUI.LargeFont); + + new GUITextBlock(new Rectangle(0, 35, 0, 20), "Submarine: ", "", saveFileFrame).Font = GUI.SmallFont; + new GUITextBlock(new Rectangle(15, 52, 0, 20), subName, "", saveFileFrame).Font = GUI.SmallFont; + + new GUITextBlock(new Rectangle(0, 70, 0, 20), "Last saved: ", "", saveFileFrame).Font = GUI.SmallFont; + new GUITextBlock(new Rectangle(15, 85, 0, 20), saveTime, "", saveFileFrame).Font = GUI.SmallFont; + + new GUITextBlock(new Rectangle(0, 105, 0, 20), "Map seed: ", "", saveFileFrame).Font = GUI.SmallFont; + new GUITextBlock(new Rectangle(15, 120, 0, 20), mapseed, "", saveFileFrame).Font = GUI.SmallFont; + + var deleteSaveButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Delete", Alignment.BottomCenter, "", saveFileFrame); + deleteSaveButton.UserData = fileName; + deleteSaveButton.OnClicked = DeleteSave; + + return true; + } + + private bool DeleteSave(GUIButton button, object obj) + { + string saveFile = obj as string; + + if (obj == null) return false; + + SaveUtil.DeleteSave(saveFile); + + UpdateLoadMenu(); + + return true; + } + + private void RemoveSaveFrame() + { + GUIComponent prevFrame = null; + foreach (GUIComponent child in loadGameContainer.children) + { + if (child.UserData as string != "savefileframe") continue; + + prevFrame = child; + break; + } + loadGameContainer.RemoveChild(prevFrame); + } + + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs index 6a484b6c5..f6fbeda1b 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs @@ -29,7 +29,7 @@ namespace Barotrauma private Level selectedLevel; - float mapZoom = 3.0f; + private float mapZoom = 3.0f; public Action StartRound; public Action OnLocationSelected; @@ -126,12 +126,11 @@ namespace Barotrauma x += 110; } - SelectTab(Tab.Crew); + SelectTab(Tab.Map); GameMain.GameSession.Map.OnLocationSelected += SelectLocation; } - private void UpdateLocationTab(Location location) { if (location.HireManager == null) @@ -163,11 +162,14 @@ namespace Barotrauma mapZoom += PlayerInput.ScrollWheelSpeed / 1000.0f; mapZoom = MathHelper.Clamp(mapZoom, 1.0f, 4.0f); - GameMain.GameSession.Map.Update((float)deltaTime, new Rectangle( - tabs[(int)selectedTab].Rect.X + 20, - tabs[(int)selectedTab].Rect.Y + 20, - tabs[(int)selectedTab].Rect.Width - 310, - tabs[(int)selectedTab].Rect.Height - 40), mapZoom); + if (GameMain.GameSession?.Map != null) + { + GameMain.GameSession.Map.Update(deltaTime, new Rectangle( + tabs[(int)selectedTab].Rect.X + 20, + tabs[(int)selectedTab].Rect.Y + 20, + tabs[(int)selectedTab].Rect.Width - 310, + tabs[(int)selectedTab].Rect.Height - 40), mapZoom); + } } public void Draw(SpriteBatch spriteBatch) @@ -179,7 +181,7 @@ namespace Barotrauma spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, GameMain.ScissorTestEnable); */ - if (selectedTab == Tab.Map) + if (selectedTab == Tab.Map && GameMain.GameSession?.Map != null) { GameMain.GameSession.Map.Draw(spriteBatch, new Rectangle( tabs[(int)selectedTab].Rect.X + 20, @@ -278,17 +280,15 @@ namespace Barotrauma if (location == null) return; - new GUITextBlock(new Rectangle(0, 0, 250, 0), location.Name, "", Alignment.TopLeft, Alignment.TopCenter, locationPanel, true, GUI.LargeFont); + var titleText = new GUITextBlock(new Rectangle(0, 0, 250, 0), location.Name, "", Alignment.TopLeft, Alignment.TopCenter, locationPanel, true, GUI.LargeFont); if (GameMain.GameSession.Map.SelectedConnection != null && GameMain.GameSession.Map.SelectedConnection.Mission != null) { var mission = GameMain.GameSession.Map.SelectedConnection.Mission; - new GUITextBlock(new Rectangle(0, 80, 0, 20), "Mission: " + mission.Name, "", locationPanel); - - new GUITextBlock(new Rectangle(0, 100, 0, 20), "Reward: " + mission.Reward + " credits", "", locationPanel); - - new GUITextBlock(new Rectangle(0, 130, 0, 0), mission.Description, "", locationPanel, true); + new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 20, 0, 20), "Mission: " + mission.Name, "", locationPanel); + new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 40, 0, 20), "Reward: " + mission.Reward + " credits", "", locationPanel); + new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 70, 0, 0), mission.Description, "", Alignment.TopLeft, Alignment.TopLeft, locationPanel, true, GUI.SmallFont); } startButton.Enabled = true; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index 2ca22e5d9..4c5826858 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -11,15 +11,12 @@ namespace Barotrauma class MainMenuScreen : Screen { public enum Tab { NewGame = 1, LoadGame = 2, HostServer = 3, Settings = 4 } - - GUIFrame buttonsTab; + + private GUIFrame buttonsTab; private GUIFrame[] menuTabs; - private GUIListBox subList; - private GUIListBox saveList; - - private GUITextBox saveNameBox, seedBox; + private CampaignSetupUI campaignSetupUI; private GUITextBox serverNameBox, portBox, passwordBox, maxPlayersBox; private GUITickBox isPublicBox, useUpnpBox; @@ -30,12 +27,10 @@ namespace Barotrauma public MainMenuScreen(GameMain game) { - menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length+1]; + menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1]; - buttonsTab = new GUIFrame(new Rectangle(0,0,0,0), Color.Transparent, Alignment.Left | Alignment.CenterY); + buttonsTab = new GUIFrame(new Rectangle(0, 0, 0, 0), Color.Transparent, Alignment.Left | Alignment.CenterY); buttonsTab.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); - //menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding; - int y = (int)(GameMain.GraphicsHeight * 0.3f); @@ -86,62 +81,17 @@ namespace Barotrauma //---------------------------------------------------------------------- menuTabs[(int)Tab.NewGame] = new GUIFrame(panelRect, ""); - menuTabs[(int)Tab.NewGame].Padding = new Vector4(20.0f,20.0f,20.0f,20.0f); - - //new GUITextBlock(new Rectangle(0, -20, 0, 30), "New Game", null, null, Alignment.CenterX, "", menuTabs[(int)Tabs.NewGame]); - - new GUITextBlock(new Rectangle(0, 0, 0, 30), "Selected submarine:", null, null, Alignment.Left, "", menuTabs[(int)Tab.NewGame]); - subList = new GUIListBox(new Rectangle(0, 30, 230, panelRect.Height-100), "", menuTabs[(int)Tab.NewGame]); - - UpdateSubList(); - - new GUITextBlock(new Rectangle((int)(subList.Rect.Width + 20), 0, 100, 20), - "Save name: ", "", Alignment.Left, Alignment.Left, menuTabs[(int)Tab.NewGame]); - - saveNameBox = new GUITextBox(new Rectangle((int)(subList.Rect.Width + 30), 30, 180, 20), - Alignment.TopLeft, "", menuTabs[(int)Tab.NewGame]); - - new GUITextBlock(new Rectangle((int)(subList.Rect.Width + 20), 60, 100, 20), - "Map Seed: ", "", Alignment.Left, Alignment.Left, menuTabs[(int)Tab.NewGame]); - - seedBox = new GUITextBox(new Rectangle((int)(subList.Rect.Width + 30), 90, 180, 20), - Alignment.TopLeft, "", menuTabs[(int)Tab.NewGame]); - seedBox.Text = ToolBox.RandomSeed(8); - - - button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, "", menuTabs[(int)Tab.NewGame]); - button.OnClicked = (GUIButton btn, object userData) => - { - Submarine selectedSub = subList.SelectedData as Submarine; - if (selectedSub != null && selectedSub.HasTag(SubmarineTag.Shuttle)) - { - var msgBox = new GUIMessageBox("Shuttle selected", - "Most shuttles are not adequately equipped to deal with the dangers of the Europan depths. "+ - "Are you sure you want to choose a shuttle as your vessel?", - new string[] {"Yes", "No"}); - - msgBox.Buttons[0].OnClicked = StartGame; - msgBox.Buttons[0].OnClicked += msgBox.Close; - - msgBox.Buttons[1].OnClicked = msgBox.Close; - return false; - } - - StartGame(btn, userData); - - return true; - }; - - //---------------------------------------------------------------------- + menuTabs[(int)Tab.NewGame].Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); menuTabs[(int)Tab.LoadGame] = new GUIFrame(panelRect, ""); - //menuTabs[(int)Tabs.LoadGame].Padding = GUI.style.smallPadding; + campaignSetupUI = new CampaignSetupUI(false, menuTabs[(int)Tab.NewGame], menuTabs[(int)Tab.LoadGame]); + campaignSetupUI.LoadGame = LoadGame; + campaignSetupUI.StartNewGame = StartGame; + + //---------------------------------------------------------------------- menuTabs[(int)Tab.HostServer] = new GUIFrame(panelRect, ""); - //menuTabs[(int)Tabs.JoinServer].Padding = GUI.style.smallPadding; - - //new GUITextBlock(new Rectangle(0, -25, 0, 30), "Host Server", "", Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer], false, GUI.LargeFont); new GUITextBlock(new Rectangle(0, 0, 100, 30), "Server Name:", "", Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tab.HostServer]); serverNameBox = new GUITextBox(new Rectangle(160, 0, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, "", menuTabs[(int)Tab.HostServer]); @@ -194,41 +144,11 @@ namespace Barotrauma Submarine.Unload(); - UpdateSubList(); + campaignSetupUI.UpdateSubList(); SelectTab(null, 0); } - private void UpdateSubList() - { - var subsToShow = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)); - - subList.ClearChildren(); - - foreach (Submarine sub in subsToShow) - { - var textBlock = new GUITextBlock( - new Rectangle(0, 0, 0, 25), - ToolBox.LimitString(sub.Name, GUI.Font, subList.Rect.Width - 65), "ListBoxElement", - Alignment.Left, Alignment.Left, subList) - { - Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f), - ToolTip = sub.Description, - UserData = sub - }; - - if (sub.HasTag(SubmarineTag.Shuttle)) - { - textBlock.TextColor = textBlock.TextColor * 0.85f; - - var shuttleText = new GUITextBlock(new Rectangle(0, 0, 0, 25), "Shuttle", "", Alignment.Left, Alignment.CenterY | Alignment.Right, textBlock, false, GUI.SmallFont); - shuttleText.TextColor = textBlock.TextColor * 0.8f; - shuttleText.ToolTip = textBlock.ToolTip; - } - } - if (Submarine.SavedSubmarines.Count > 0) subList.Select(Submarine.SavedSubmarines[0]); - } - public bool SelectTab(GUIButton button, object obj) { try @@ -276,10 +196,10 @@ namespace Barotrauma switch (selectedTab) { case Tab.NewGame: - saveNameBox.Text = SaveUtil.CreateSavePath(); + campaignSetupUI.CreateDefaultSaveName(); break; case Tab.LoadGame: - UpdateLoadScreen(); + campaignSetupUI.UpdateLoadMenu(); break; case Tab.Settings: GameMain.Config.ResetSettingsFrame(); @@ -379,99 +299,6 @@ namespace Barotrauma return true; } - private void UpdateLoadScreen() - { - menuTabs[(int)Tab.LoadGame].ClearChildren(); - - string[] saveFiles = SaveUtil.GetSaveFiles(); - - saveList = new GUIListBox(new Rectangle(0, 0, 200, menuTabs[(int)Tab.LoadGame].Rect.Height - 80), Color.White, "", menuTabs[(int)Tab.LoadGame]); - saveList.OnSelected = SelectSaveFile; - - foreach (string saveFile in saveFiles) - { - GUITextBlock textBlock = new GUITextBlock( - new Rectangle(0, 0, 0, 25), - saveFile, - "ListBoxElement", - Alignment.Left, - Alignment.Left, - saveList); - textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); - textBlock.UserData = saveFile; - } - - var button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.Right | Alignment.Bottom, "", menuTabs[(int)Tab.LoadGame]); - button.OnClicked = LoadGame; - } - - private bool SelectSaveFile(GUIComponent component, object obj) - { - string fileName = (string)obj; - - XDocument doc = SaveUtil.LoadGameSessionDoc(fileName); - - if (doc==null) - { - DebugConsole.ThrowError("Error loading save file \""+fileName+"\". The file may be corrupted."); - return false; - } - - RemoveSaveFrame(); - - string subName = ToolBox.GetAttributeString(doc.Root, "submarine", ""); - - string saveTime = ToolBox.GetAttributeString(doc.Root, "savetime", "unknown"); - - string mapseed = ToolBox.GetAttributeString(doc.Root, "mapseed", "unknown"); - - GUIFrame saveFileFrame = new GUIFrame(new Rectangle((int)(saveList.Rect.Width + 20), 0, 200, 230), Color.Black*0.4f, "", menuTabs[(int)Tab.LoadGame]); - saveFileFrame.UserData = "savefileframe"; - saveFileFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); - - new GUITextBlock(new Rectangle(0,0,0,20), fileName, "", Alignment.TopLeft, Alignment.TopLeft, saveFileFrame, false, GUI.LargeFont); - - new GUITextBlock(new Rectangle(0, 35, 0, 20), "Submarine: ", "", saveFileFrame).Font = GUI.SmallFont; - new GUITextBlock(new Rectangle(15, 52, 0, 20), subName, "", saveFileFrame).Font = GUI.SmallFont; - - new GUITextBlock(new Rectangle(0, 70, 0, 20), "Last saved: ", "", saveFileFrame).Font = GUI.SmallFont; - new GUITextBlock(new Rectangle(15, 85, 0, 20), saveTime, "", saveFileFrame).Font = GUI.SmallFont; - - new GUITextBlock(new Rectangle(0, 105, 0, 20), "Map seed: ", "", saveFileFrame).Font = GUI.SmallFont; - new GUITextBlock(new Rectangle(15, 120, 0, 20), mapseed, "", saveFileFrame).Font = GUI.SmallFont; - - var deleteSaveButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Delete", Alignment.BottomCenter, "", saveFileFrame); - deleteSaveButton.UserData = fileName; - deleteSaveButton.OnClicked = DeleteSave; - - return true; - } - - private bool DeleteSave(GUIButton button, object obj) - { - string saveFile = obj as string; - - if (obj == null) return false; - - SaveUtil.DeleteSave(saveFile); - - UpdateLoadScreen(); - - return true; - } - - private void RemoveSaveFrame() - { - GUIComponent prevFrame = null; - foreach (GUIComponent child in menuTabs[(int)Tab.LoadGame].children) - { - if (child.UserData as string != "savefileframe") continue; - - prevFrame = child; - break; - } - menuTabs[(int)Tab.LoadGame].RemoveChild(prevFrame); - } public override void AddToGUIUpdateList() { @@ -513,53 +340,42 @@ namespace Barotrauma spriteBatch.End(); } - private bool StartGame(GUIButton button, object userData) + private void StartGame(Submarine selectedSub, string saveName, string mapSeed) { - if (string.IsNullOrEmpty(saveNameBox.Text)) return false; + if (string.IsNullOrEmpty(saveName)) return; - string[] existingSaveFiles = SaveUtil.GetSaveFiles(); + string[] existingSaveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Singleplayer); - if (Array.Find(existingSaveFiles, s => s == saveNameBox.Text)!=null) + if (Array.Find(existingSaveFiles, s => s == saveName) != null) { new GUIMessageBox("Save name already in use", "Please choose another name for the save file"); - return false; + return; } - - Submarine selectedSub = subList.SelectedData as Submarine; + if (selectedSub == null) { new GUIMessageBox("Submarine not selected", "Please select a submarine"); - return false; + return; } - + if (!Directory.Exists(SaveUtil.TempPath)) { Directory.CreateDirectory(SaveUtil.TempPath); } - File.Copy(selectedSub.FilePath, Path.Combine(SaveUtil.TempPath, selectedSub.Name+".sub"), true); + File.Copy(selectedSub.FilePath, Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"), true); selectedSub = new Submarine(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"), ""); - - GameMain.GameSession = new GameSession(selectedSub, saveNameBox.Text, GameModePreset.list.Find(gm => gm.Name == "Single Player")); - (GameMain.GameSession.GameMode as CampaignMode).GenerateMap(seedBox.Text); + + GameMain.GameSession = new GameSession(selectedSub, saveName, GameModePreset.list.Find(gm => gm.Name == "Single Player")); + (GameMain.GameSession.GameMode as CampaignMode).GenerateMap(mapSeed); GameMain.LobbyScreen.Select(); - - return true; } - - private bool PreviousTab(GUIButton button, object obj) + + private void LoadGame(string saveFile) { - //selectedTab = (int)Tabs.Main; - - return true; - } - - private bool LoadGame(GUIButton button, object obj) - { - string saveFile = saveList.SelectedData as string; - if (string.IsNullOrWhiteSpace(saveFile)) return false; + if (string.IsNullOrWhiteSpace(saveFile)) return; try { @@ -568,13 +384,11 @@ namespace Barotrauma catch (Exception e) { DebugConsole.ThrowError("Loading save \""+saveFile+"\" failed", e); - return false; + return; } GameMain.LobbyScreen.Select(); - - return true; } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 90a28fb9c..b58c0c412 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -34,6 +34,10 @@ namespace Barotrauma private GUITextBox textBox, seedBox; + private GUIFrame defaultModeContainer, campaignContainer; + + private GUIButton campaignViewButton; + private GUIFrame myPlayerFrame; private GUIFrame jobInfoFrame; @@ -44,6 +48,8 @@ namespace Barotrauma private GUIDropDown shuttleList; + private CampaignUI campaignUI; + private Sprite backgroundSprite; private GUITextBox serverMessage; @@ -215,37 +221,43 @@ namespace Barotrauma playerList = new GUIListBox(new Rectangle(0, 0, 0, 0), null, "", playerListFrame); playerList.OnSelected = SelectPlayer; + defaultModeContainer = new GUIFrame(new Rectangle(0, 10, 0, 0), null, infoFrame); + + campaignContainer = new GUIFrame(new Rectangle(0, 20, 0, 0), null, infoFrame); + campaignContainer.Visible = false; + var backButton = new GUIButton(new Rectangle(0, -20, 100, 30), "Back", "", campaignContainer); + backButton.OnClicked += (btn, obj) => { ToggleCampaignView(false); return true; }; + + //submarine list ------------------------------------------------------------------ int columnWidth = infoFrame.Rect.Width / 3 - 5; int columnX = 0; - new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Submarine:", "", infoFrame); - subList = new GUIListBox(new Rectangle(columnX, 150, columnWidth, infoFrame.Rect.Height - 150 - 80), Color.White, "", infoFrame); + new GUITextBlock(new Rectangle(columnX, 110, columnWidth, 30), "Submarine:", "", defaultModeContainer); + subList = new GUIListBox(new Rectangle(columnX, 140, columnWidth, defaultModeContainer.Rect.Height - 170), Color.White, "", defaultModeContainer); subList.OnSelected = VotableClicked; - var voteText = new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Votes: ", "", Alignment.TopLeft, Alignment.TopRight, infoFrame); + var voteText = new GUITextBlock(new Rectangle(columnX, 110, columnWidth, 30), "Votes: ", "", Alignment.TopLeft, Alignment.TopRight, defaultModeContainer); voteText.UserData = "subvotes"; voteText.Visible = false; - - //UpdateSubList(Submarine.SavedSubmarines); - + columnX += columnWidth + 20; //respawn shuttle ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 120, 20, 20), "Respawn shuttle:", "", infoFrame); - shuttleList = new GUIDropDown(new Rectangle(columnX, 150, 200, 20), "", "", infoFrame); + new GUITextBlock(new Rectangle(columnX, 110, 20, 20), "Respawn shuttle:", "", defaultModeContainer); + shuttleList = new GUIDropDown(new Rectangle(columnX, 140, 200, 20), "", "", defaultModeContainer); //gamemode ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 180, 0, 30), "Game mode: ", "", infoFrame); - modeList = new GUIListBox(new Rectangle(columnX, 200, columnWidth, infoFrame.Rect.Height - 300), "", infoFrame); + new GUITextBlock(new Rectangle(columnX, 170, 0, 30), "Game mode: ", "", defaultModeContainer); + modeList = new GUIListBox(new Rectangle(columnX, 200, columnWidth, defaultModeContainer.Rect.Height - 230), "", defaultModeContainer); modeList.OnSelected = VotableClicked; - voteText = new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Votes: ", "", Alignment.TopLeft, Alignment.TopRight, infoFrame); + voteText = new GUITextBlock(new Rectangle(columnX, 170, columnWidth, 30), "Votes: ", "", Alignment.TopLeft, Alignment.TopRight, defaultModeContainer); voteText.UserData = "modevotes"; voteText.Visible = false; @@ -265,7 +277,7 @@ namespace Barotrauma //mission type ------------------------------------------------------------------ - missionTypeBlock = new GUITextBlock(new Rectangle(columnX, -10, 300, 20), "Mission type:", "", Alignment.BottomLeft, Alignment.CenterLeft, infoFrame); + missionTypeBlock = new GUITextBlock(new Rectangle(columnX, -10, 300, 20), "Mission type:", "", Alignment.BottomLeft, Alignment.CenterLeft, defaultModeContainer); missionTypeBlock.Padding = Vector4.Zero; missionTypeBlock.UserData = 0; @@ -296,46 +308,46 @@ namespace Barotrauma //seed ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 120, 180, 20), - "Level Seed: ", "", Alignment.Left, Alignment.TopLeft, infoFrame); + new GUITextBlock(new Rectangle(columnX, 110, 180, 20), + "Level Seed: ", "", Alignment.Left, Alignment.TopLeft, defaultModeContainer); - seedBox = new GUITextBox(new Rectangle(columnX, 150, columnWidth / 2, 20), - Alignment.TopLeft, "", infoFrame); + seedBox = new GUITextBox(new Rectangle(columnX, 140, columnWidth / 2, 20), + Alignment.TopLeft, "", defaultModeContainer); seedBox.OnTextChanged = SelectSeed; LevelSeed = ToolBox.RandomSeed(8); //traitor probability ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 180, 20, 20), "Traitors:", "", infoFrame); + new GUITextBlock(new Rectangle(columnX, 170, 20, 20), "Traitors:", "", defaultModeContainer); traitorProbabilityButtons = new GUIButton[2]; - traitorProbabilityButtons[0] = new GUIButton(new Rectangle(columnX, 205, 20, 20), "<", "", infoFrame); + traitorProbabilityButtons[0] = new GUIButton(new Rectangle(columnX, 195, 20, 20), "<", "", defaultModeContainer); traitorProbabilityButtons[0].UserData = -1; - traitorProbabilityText = new GUITextBlock(new Rectangle(columnX + 20, 205, 80, 20), "No", null, null, Alignment.Center, "", infoFrame); + traitorProbabilityText = new GUITextBlock(new Rectangle(columnX + 20, 195, 80, 20), "No", null, null, Alignment.Center, "", defaultModeContainer); - traitorProbabilityButtons[1] = new GUIButton(new Rectangle(columnX + 100, 205, 20, 20), ">", "", infoFrame); + traitorProbabilityButtons[1] = new GUIButton(new Rectangle(columnX + 100, 195, 20, 20), ">", "", defaultModeContainer); traitorProbabilityButtons[1].UserData = 1; //automatic restart ------------------------------------------------------------------ - autoRestartBox = new GUITickBox(new Rectangle(columnX, 240, 20, 20), "Automatic restart", Alignment.TopLeft, infoFrame); + autoRestartBox = new GUITickBox(new Rectangle(columnX, 230, 20, 20), "Automatic restart", Alignment.TopLeft, defaultModeContainer); autoRestartBox.OnSelected = ToggleAutoRestart; - var restartText = new GUITextBlock(new Rectangle(columnX, 265, 20, 20), "", "", infoFrame); + var restartText = new GUITextBlock(new Rectangle(columnX, 255, 20, 20), "", "", defaultModeContainer); restartText.Font = GUI.SmallFont; restartText.TextGetter = AutoRestartText; //server info ------------------------------------------------------------------ - var serverName = new GUITextBox(new Rectangle(0, 0, 200, 20), null, null, Alignment.TopLeft, Alignment.TopLeft, "", infoFrame); + var serverName = new GUITextBox(new Rectangle(0, 0, 200, 20), null, null, Alignment.TopLeft, Alignment.TopLeft, "", defaultModeContainer); serverName.TextGetter = GetServerName; serverName.Enabled = GameMain.Server != null; serverName.OnTextChanged = ChangeServerName; - serverMessage = new GUITextBox(new Rectangle(0, 30, 360, 70), null, null, Alignment.TopLeft, Alignment.TopLeft, "", infoFrame); + serverMessage = new GUITextBox(new Rectangle(0, 30, 360, 70), null, null, Alignment.TopLeft, Alignment.TopLeft, "", defaultModeContainer); serverMessage.Wrap = true; serverMessage.OnTextChanged = UpdateServerMessage; @@ -422,10 +434,14 @@ namespace Barotrauma missionTypeButtons[0].OnClicked = ToggleMissionType; missionTypeButtons[1].OnClicked = ToggleMissionType; - StartButton = new GUIButton(new Rectangle(0, 0, 80, 30), "Start", Alignment.BottomRight, "", infoFrame); + StartButton = new GUIButton(new Rectangle(0, 0, 80, 30), "Start", Alignment.BottomRight, "", defaultModeContainer); StartButton.OnClicked = GameMain.Server.StartGameClicked; - GUIButton settingsButton = new GUIButton(new Rectangle(-100, 0, 80, 30), "Settings", Alignment.BottomRight, "", infoFrame); + campaignViewButton = new GUIButton(new Rectangle(0, 0, 130, 30), "Campaign view", Alignment.BottomRight, "", defaultModeContainer); + campaignViewButton.OnClicked = (btn, obj) => { ToggleCampaignView(true); return true; }; + campaignViewButton.Visible = false; + + GUIButton settingsButton = new GUIButton(new Rectangle(-110, 0, 80, 20), "Settings", Alignment.TopRight, "", infoFrame); settingsButton.OnClicked = GameMain.Server.ToggleSettingsFrame; settingsButton.UserData = "settingsButton"; @@ -983,6 +999,12 @@ namespace Barotrauma menu.Update((float)deltaTime); } + if (campaignContainer.Visible && campaignUI != null) + { + campaignContainer.Update((float)deltaTime); + campaignUI.Update((float)deltaTime); + } + if (autoRestartTimer != 0.0f && autoRestartBox.Selected) { autoRestartTimer = Math.Max(autoRestartTimer - (float)deltaTime, 0.0f); @@ -1009,6 +1031,11 @@ namespace Barotrauma if (playerFrame != null) playerFrame.Draw(spriteBatch); + if (campaignContainer.Visible && campaignUI != null) + { + campaignUI.Draw(spriteBatch); + } + GUI.Draw((float)deltaTime, spriteBatch, null); spriteBatch.End(); @@ -1071,27 +1098,50 @@ namespace Barotrauma { modeList.Select(modeIndex, true); + ToggleCampaignMode(SelectedMode.Name == "Campaign"); missionTypeBlock.Visible = SelectedMode != null && SelectedMode.Name == "Mission"; } private bool SelectMode(GUIComponent component, object obj) { if (GameMain.NetworkMember == null) return false; - - //if (GameMain.Server==null) - //{ - // return VotableClicked(component, obj); - //} - + GameModePreset modePreset = obj as GameModePreset; if (modePreset == null) return false; - + missionTypeBlock.Visible = modePreset.Name == "Mission"; - lastUpdateID++; + + if (modePreset.Name == "Campaign") + { + MultiplayerCampaign.StartCampaignSetup(); + } + lastUpdateID++; return true; } + public void ToggleCampaignView(bool enabled) + { + defaultModeContainer.Visible = !enabled; + StartButton.Visible = !enabled; + + campaignContainer.Visible = enabled; + } + + public void ToggleCampaignMode(bool enabled) + { + StartButton.Visible = !enabled; + campaignViewButton.Visible = enabled; + + ToggleCampaignView(enabled); + + if (enabled && campaignUI == null) + { + campaignUI = new CampaignUI(GameMain.GameSession.GameMode as CampaignMode, campaignContainer); + campaignUI.StartRound = () => { GameMain.Server.StartGame(); }; + } + } + private bool SelectSeed(GUITextBox textBox, string seed) { if (GameMain.Server == null) return false; @@ -1102,26 +1152,7 @@ namespace Barotrauma return true; } - - //private bool ChangeCharacterName(GUITextBox textBox, string newName) - //{ - // if (string.IsNullOrEmpty(newName)) return false; - - // if (GameMain.NetworkMember == null || GameMain.NetworkMember.CharacterInfo == null) return true; - - // GameMain.NetworkMember.CharacterInfo.Name = newName; - // if (GameMain.Client != null) - // { - // GameMain.Client.Name = newName; - // GameMain.Client.SendCharacterData(); - // } - - // textBox.Text = newName; - // textBox.Selected = false; - - // return true; - //} - + private bool ViewJobInfo(GUIButton button, object obj) { GUIComponent jobText = button.Parent; diff --git a/Barotrauma/BarotraumaClient/Source/Utils/SaveUtil.cs b/Barotrauma/BarotraumaClient/Source/Utils/SaveUtil.cs deleted file mode 100644 index 6a0fa9cd1..000000000 --- a/Barotrauma/BarotraumaClient/Source/Utils/SaveUtil.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Xml.Linq; - -namespace Barotrauma -{ - public partial class SaveUtil - { - public static void SaveGame(string fileName) - { - fileName = Path.Combine(SaveFolder, fileName); - - string tempPath = Path.Combine(SaveFolder, "temp"); - - Directory.CreateDirectory(tempPath); - try - { - ClearFolder(tempPath, new string[] { GameMain.GameSession.Submarine.FilePath }); - } - catch - { - - } - - try - { - if (Submarine.MainSub != null && Submarine.Loaded.Contains(Submarine.MainSub)) - { - Submarine.MainSub.FilePath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub"); - Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath); - } - } - catch (Exception e) - { - DebugConsole.ThrowError("Error saving submarine", e); - } - - try - { - GameMain.GameSession.Save(Path.Combine(tempPath, "gamesession.xml")); - } - - catch (Exception e) - { - DebugConsole.ThrowError("Error saving gamesession", e); - } - - try - { - CompressDirectory(tempPath, fileName+".save", null); - } - - catch (Exception e) - { - DebugConsole.ThrowError("Error compressing save file", e); - } - } - - public static void LoadGame(string fileName) - { - string filePath = Path.Combine(SaveFolder, fileName+".save"); - - DecompressToDirectory(filePath, TempPath, null); - - XDocument doc = ToolBox.TryLoadXml(Path.Combine(TempPath, "gamesession.xml")); - - string subPath = Path.Combine(TempPath, ToolBox.GetAttributeString(doc.Root, "submarine", ""))+".sub"; - Submarine selectedMap = new Submarine(subPath, "");// Submarine.Load(); - GameMain.GameSession = new GameSession(selectedMap, fileName, doc); - - //Directory.Delete(tempPath, true); - } - - public static XDocument LoadGameSessionDoc(string fileName) - { - string filePath = Path.Combine(SaveFolder, fileName + ".save"); - - string tempPath = Path.Combine(SaveFolder, "temp"); - - try - { - DecompressToDirectory(filePath, tempPath, null); - } - catch - { - return null; - } - - return ToolBox.TryLoadXml(Path.Combine(tempPath, "gamesession.xml")); - } - - public static void DeleteSave(string fileName) - { - fileName = Path.Combine(SaveFolder, fileName + ".save"); - - try - { - File.Delete(fileName); - } - - catch (Exception e) - { - DebugConsole.ThrowError("ERROR: deleting save file \""+fileName+" failed.", e); - } - - } - - public static string[] GetSaveFiles() - { - if (!Directory.Exists(SaveFolder)) - { - DebugConsole.ThrowError("Save folder \"" + SaveFolder + " not found! Attempting to create a new folder"); - try - { - Directory.CreateDirectory(SaveFolder); - } - catch (Exception e) - { - DebugConsole.ThrowError("Failed to create the folder \"" + SaveFolder + "\"!", e); - } - } - - string[] files = Directory.GetFiles(SaveFolder, "*.save"); - - for (int i = 0; i < files.Length; i++) - { - files[i] = Path.GetFileNameWithoutExtension(files[i]); - } - - return files; - } - - public static string CreateSavePath(string fileName="Save") - { - if (!Directory.Exists(SaveFolder)) - { - DebugConsole.ThrowError("Save folder \""+SaveFolder+"\" not found. Created new folder"); - Directory.CreateDirectory(SaveFolder); - } - - string extension = ".save"; - string pathWithoutExtension = Path.Combine(SaveFolder, fileName); - - int i = 0; - while (File.Exists(pathWithoutExtension + " " + i + extension)) - { - i++; - } - - return fileName + " " + i; - } - - public static void CompressStringToFile(string fileName, string value) - { - // A. - // Write string to temporary file. - string temp = Path.GetTempFileName(); - File.WriteAllText(temp, value); - - // B. - // Read file into byte array buffer. - byte[] b; - using (FileStream f = new FileStream(temp, FileMode.Open)) - { - b = new byte[f.Length]; - f.Read(b, 0, (int)f.Length); - } - - // C. - // Use GZipStream to write compressed bytes to target file. - using (FileStream f2 = new FileStream(fileName, FileMode.Create)) - using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) - { - gz.Write(b, 0, b.Length); - } - } - - public static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream) - { - //Compress file name - char[] chars = sRelativePath.ToCharArray(); - zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int)); - foreach (char c in chars) - zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char)); - - //Compress file content - byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath)); - zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int)); - zipStream.Write(bytes, 0, bytes.Length); - } - - public static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress) - { - string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories); - int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1; - - using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None)) - using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress)) - foreach (string sFilePath in sFiles) - { - string sRelativePath = sFilePath.Substring(iDirLen); - if (progress != null) - progress(sRelativePath); - CompressFile(sInDir, sRelativePath, str); - } - } - - private static void ClearFolder(string FolderName, string[] ignoredFiles = null) - { - DirectoryInfo dir = new DirectoryInfo(FolderName); - - foreach (FileInfo fi in dir.GetFiles()) - { - bool ignore = false; - foreach (string ignoredFile in ignoredFiles) - { - if (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile))) - { - ignore = true; - break; - } - } - - if (ignore) continue; - - fi.IsReadOnly = false; - fi.Delete(); - } - - foreach (DirectoryInfo di in dir.GetDirectories()) - { - ClearFolder(di.FullName, ignoredFiles); - di.Delete(); - } - } - } -} diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/GameModePreset.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/GameModePreset.cs index 1ac071102..7bc0c9278 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/GameModePreset.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/GameModePreset.cs @@ -37,7 +37,6 @@ namespace Barotrauma new GameModePreset("Single Player", typeof(SinglePlayerCampaign), true); new GameModePreset("Tutorial", typeof(TutorialMode), true); #endif - new GameModePreset("Campaign", typeof(MultiplayerCampaign), false); var mode = new GameModePreset("SandBox", typeof(GameMode), false); mode.Description = "A game mode with no specific objectives."; @@ -46,6 +45,8 @@ namespace Barotrauma mode.Description = "The crew must work together to complete a specific task, such as retrieving " + "an alien artifact or killing a creature that's terrorizing nearby outposts. The game ends " + "when the task is completed or everyone in the crew has died."; + + new GameModePreset("Campaign", typeof(MultiplayerCampaign), false); } } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs index 3d67f4260..430de6d1e 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs @@ -1,5 +1,7 @@ -using System; +using Microsoft.Xna.Framework; +using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.Xml.Linq; @@ -7,14 +9,172 @@ namespace Barotrauma { class MultiplayerCampaign : CampaignMode { + public MultiplayerCampaign(GameModePreset preset, object param) : base(preset, param) { } +#if CLIENT + public static void StartCampaignSetup() + { + var setupBox = new GUIMessageBox("Campaign Setup", "", new string [0], 500, 500); + setupBox.InnerFrame.Padding = new Vector4(20.0f, 80.0f, 20.0f, 20.0f); + + var newCampaignContainer = new GUIFrame(new Rectangle(0,40,0,0), null, setupBox.InnerFrame); + var loadCampaignContainer = new GUIFrame(new Rectangle(0, 40, 0, 0), null, setupBox.InnerFrame); + + var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer); + + var newCampaignButton = new GUIButton(new Rectangle(0,0,120,20), "New campaign", "", setupBox.InnerFrame); + newCampaignButton.OnClicked += (btn, obj) => + { + newCampaignContainer.Visible = true; + loadCampaignContainer.Visible = false; + return true; + }; + + var loadCampaignButton = new GUIButton(new Rectangle(130, 0, 120, 20), "Load campaign", "", setupBox.InnerFrame); + loadCampaignButton.OnClicked += (btn, obj) => + { + newCampaignContainer.Visible = false; + loadCampaignContainer.Visible = true; + return true; + }; + + loadCampaignContainer.Visible = false; + + campaignSetupUI.StartNewGame = (Submarine sub, string saveName, string mapSeed) => + { + GameMain.GameSession = new GameSession(sub, saveName, GameModePreset.list.Find(g => g.Name == "Campaign")); + var campaign = ((MultiplayerCampaign)GameMain.GameSession.GameMode); + campaign.GenerateMap(mapSeed); + setupBox.Close(); + + GameMain.NetLobbyScreen.ToggleCampaignMode(true); + }; + + campaignSetupUI.LoadGame = (string fileName) => + { + SaveUtil.LoadGame(fileName); + setupBox.Close(); + + GameMain.NetLobbyScreen.ToggleCampaignMode(true); + }; + } + +#endif + + + public override void End(string endMessage = "") + { + isRunning = false; + + bool success = + GameMain.Server.ConnectedClients.Any(c => c.inGame && c.Character != null && !c.Character.IsDead) || + (GameMain.Server.Character != null && !GameMain.Server.Character.IsDead); + + /*if (success) + { + if (subsToLeaveBehind == null || leavingSub == null) + { + DebugConsole.ThrowError("Leaving submarine not selected -> selecting the closest one"); + + leavingSub = GetLeavingSub(); + + subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub); + } + }*/ + + GameMain.GameSession.EndRound(""); + + if (success) + { + bool atEndPosition = Submarine.MainSub.AtEndPosition; + + /*if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub)) + { + Submarine.MainSub = leavingSub; + + GameMain.GameSession.Submarine = leavingSub; + + foreach (Submarine sub in subsToLeaveBehind) + { + MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine); + LinkedSubmarine.CreateDummy(leavingSub, sub); + } + }*/ + + if (atEndPosition) + { + Map.MoveToNextLocation(); + } + + SaveUtil.SaveGame(GameMain.GameSession.SaveFile); + } + + + if (!success) + { + /* var summaryScreen = GUIMessageBox.VisibleBox; + + if (summaryScreen != null) + { + summaryScreen = summaryScreen.children[0]; + summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton)); + + var okButton = new GUIButton(new Rectangle(-120, 0, 100, 30), "Load game", Alignment.BottomRight, "", summaryScreen); + okButton.OnClicked += GameMain.GameSession.LoadPrevious; + okButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; }; + + var quitButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Quit", Alignment.BottomRight, "", summaryScreen); + quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu; + quitButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; }; + }*/ + } + + for (int i = Character.CharacterList.Count - 1; i >= 0; i--) + { + Character.CharacterList[i].Remove(); + } + + Submarine.Unload(); + } + + public static MultiplayerCampaign Load(XElement element) + { + MultiplayerCampaign campaign = new MultiplayerCampaign(GameModePreset.list.Find(gm => gm.Name == "Campaign"), null); + + foreach (XElement subElement in element.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "map": + campaign.map = Map.Load(subElement); + break; + } + } + + campaign.Money = ToolBox.GetAttributeInt(element, "money", 0); + + //backwards compatibility with older save files + if (campaign.map == null) + { + string mapSeed = ToolBox.GetAttributeString(element, "mapseed", "a"); + campaign.GenerateMap(mapSeed); + campaign.map.SetLocation(ToolBox.GetAttributeInt(element, "currentlocation", 0)); + } + + //campaign.savedOnStart = true; + return campaign; + } + public override void Save(XElement element) { - throw new NotImplementedException(); + XElement modeElement = new XElement("MultiPlayerCampaign"); + modeElement.Add(new XAttribute("money", Money)); + Map.Save(modeElement); + element.Add(modeElement); } } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index c4570f4b0..624ea661d 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -1,4 +1,5 @@ using Microsoft.Xna.Framework; +using System; using System.Xml.Linq; namespace Barotrauma @@ -112,14 +113,23 @@ namespace Barotrauma #if CLIENT CrewManager = new CrewManager(); - +#endif foreach (XElement subElement in doc.Root.Elements()) { - if (subElement.Name.ToString().ToLowerInvariant() != "gamemode") continue; - - GameMode = SinglePlayerCampaign.Load(subElement); - } + switch (subElement.Name.ToString().ToLowerInvariant()) + { +#if CLIENT + case "gamemode": //legacy support + case "singleplayercampaign": + GameMode = SinglePlayerCampaign.Load(subElement); + break; #endif + case "multiplayercampaign": + GameMode = MultiplayerCampaign.Load(subElement); + break; + } + } + } private void CreateDummyLocations() @@ -255,5 +265,32 @@ namespace Barotrauma #endif } + public void Save(string filePath) + { + if (!(GameMode is CampaignMode)) + { + throw new NotSupportedException("GameSessions can only be saved when playing in a campaign mode."); + } + + XDocument doc = new XDocument( + new XElement("Gamesession")); + + var now = DateTime.Now; + doc.Root.Add(new XAttribute("savetime", now.ToShortTimeString() + ", " + now.ToShortDateString())); + doc.Root.Add(new XAttribute("submarine", submarine == null ? "" : submarine.Name)); + doc.Root.Add(new XAttribute("mapseed", Map.Seed)); + + ((CampaignMode)GameMode).Save(doc.Root); + + try + { + doc.Save(filePath); + } + catch + { + DebugConsole.ThrowError("Saving gamesession to \"" + filePath + "\" failed!"); + } + } + } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs index b6a52a02f..e57fe615d 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs @@ -351,6 +351,31 @@ namespace Barotrauma currentLocation = locations[index]; currentLocation.Discovered = true; } + + public void Save(XElement element) + { + XElement mapElement = new XElement("map"); + + mapElement.Add(new XAttribute("currentlocation", CurrentLocationIndex)); + mapElement.Add(new XAttribute("seed", Seed)); + mapElement.Add(new XAttribute("size", size)); + + List discoveredLocations = new List(); + for (int i = 0; i < locations.Count; i++) + { + if (locations[i].Discovered) discoveredLocations.Add(i); + } + mapElement.Add(new XAttribute("discovered", string.Join(",", discoveredLocations))); + + List passedConnections = new List(); + for (int i = 0; i < connections.Count; i++) + { + if (connections[i].Passed) passedConnections.Add(i); + } + mapElement.Add(new XAttribute("passed", string.Join(",", passedConnections))); + + element.Add(mapElement); + } } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index a9e7acd8e..55b9c3298 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -1128,8 +1128,16 @@ namespace Barotrauma.Networking int teamCount = 1; byte hostTeam = 1; + + string levelSeed = GameMain.NetLobbyScreen.LevelSeed; + + MultiplayerCampaign campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; - GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, Mission.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]); + //don't instantiate a new gamesession if we're playing a campaign + if (campaign == null || GameMain.GameSession == null) + { + GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, Mission.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]); + } if (GameMain.GameSession.GameMode.Mission != null && GameMain.GameSession.GameMode.Mission.AssignTeamIDs(connectedClients, out hostTeam)) @@ -1141,7 +1149,14 @@ namespace Barotrauma.Networking connectedClients.ForEach(c => c.TeamID = hostTeam); } - GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, teamCount > 1); + if (campaign != null) + { + GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level, true, teamCount > 1); + } + else + { + GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, teamCount > 1); + } GameServer.Log("Starting a new round...", ServerLog.MessageType.ServerMessage); GameServer.Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage); diff --git a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs index 3fa1447fa..99275570d 100644 --- a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs +++ b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs @@ -2,12 +2,14 @@ using System.IO; using System.IO.Compression; using System.Text; +using System.Xml.Linq; namespace Barotrauma { public partial class SaveUtil { - public static string SaveFolder = "Data"+Path.DirectorySeparatorChar+"Saves"; + public static string SaveFolder = "Data" + Path.DirectorySeparatorChar + "Saves"; + public static string MultiplayerSaveFolder = "Data" + Path.DirectorySeparatorChar + "Saves" + Path.DirectorySeparatorChar + "Multiplayer"; public delegate void ProgressDelegate(string sMessage); @@ -16,26 +18,225 @@ namespace Barotrauma get { return Path.Combine(SaveFolder, "temp"); } } + public enum SaveType + { + Singleplayer, + Multiplayer + } + + public static void SaveGame(string filePath) + { + string tempPath = Path.Combine(SaveFolder, "temp"); + + Directory.CreateDirectory(tempPath); + try + { + ClearFolder(tempPath, new string[] { GameMain.GameSession.Submarine.FilePath }); + } + catch + { + + } + + try + { + if (Submarine.MainSub != null && Submarine.Loaded.Contains(Submarine.MainSub)) + { + Submarine.MainSub.FilePath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub"); + Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath); + } + } + catch (Exception e) + { + DebugConsole.ThrowError("Error saving submarine", e); + } + + try + { + GameMain.GameSession.Save(Path.Combine(tempPath, "gamesession.xml")); + } + + catch (Exception e) + { + DebugConsole.ThrowError("Error saving gamesession", e); + } + + try + { + CompressDirectory(tempPath, filePath, null); + } + + catch (Exception e) + { + DebugConsole.ThrowError("Error compressing save file", e); + } + } + + public static void LoadGame(string filePath) + { + DecompressToDirectory(filePath, TempPath, null); + + XDocument doc = ToolBox.TryLoadXml(Path.Combine(TempPath, "gamesession.xml")); + + string subPath = Path.Combine(TempPath, ToolBox.GetAttributeString(doc.Root, "submarine", "")) + ".sub"; + Submarine selectedMap = new Submarine(subPath, ""); + GameMain.GameSession = new GameSession(selectedMap, filePath, doc); + } + + public static XDocument LoadGameSessionDoc(string filePath) + { + string tempPath = Path.Combine(SaveFolder, "temp"); + + try + { + DecompressToDirectory(filePath, tempPath, null); + } + catch + { + return null; + } + + return ToolBox.TryLoadXml(Path.Combine(tempPath, "gamesession.xml")); + } + + public static void DeleteSave(string filePath) + { + //filePath = Path.Combine(SaveFolder, filePath + ".save"); + + try + { + File.Delete(filePath); + } + + catch (Exception e) + { + DebugConsole.ThrowError("ERROR: deleting save file \"" + filePath + " failed.", e); + } + } + + public static string[] GetSaveFiles(SaveType saveType) + { + string folder = saveType == SaveType.Singleplayer ? SaveFolder : MultiplayerSaveFolder; + + if (!Directory.Exists(folder)) + { + DebugConsole.ThrowError("Save folder \"" + folder + " not found! Attempting to create a new folder"); + try + { + Directory.CreateDirectory(folder); + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to create the folder \"" + folder + "\"!", e); + } + } + + string[] files = Directory.GetFiles(folder, "*.save"); + + /*for (int i = 0; i < files.Length; i++) + { + files[i] = Path.GetFileNameWithoutExtension(files[i]); + }*/ + + return files; + } + + public static string CreateSavePath(string fileName = "Save") + { + if (!Directory.Exists(SaveFolder)) + { + DebugConsole.ThrowError("Save folder \"" + SaveFolder + "\" not found. Created new folder"); + Directory.CreateDirectory(SaveFolder); + } + + string extension = ".save"; + string pathWithoutExtension = Path.Combine(SaveFolder, fileName); + + int i = 0; + while (File.Exists(pathWithoutExtension + " " + i + extension)) + { + i++; + } + + return pathWithoutExtension + " " + i; + } + + public static void CompressStringToFile(string fileName, string value) + { + // A. + // Write string to temporary file. + string temp = Path.GetTempFileName(); + File.WriteAllText(temp, value); + + // B. + // Read file into byte array buffer. + byte[] b; + using (FileStream f = new FileStream(temp, FileMode.Open)) + { + b = new byte[f.Length]; + f.Read(b, 0, (int)f.Length); + } + + // C. + // Use GZipStream to write compressed bytes to target file. + using (FileStream f2 = new FileStream(fileName, FileMode.Create)) + using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) + { + gz.Write(b, 0, b.Length); + } + } + + public static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream) + { + //Compress file name + char[] chars = sRelativePath.ToCharArray(); + zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int)); + foreach (char c in chars) + zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char)); + + //Compress file content + byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath)); + zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int)); + zipStream.Write(bytes, 0, bytes.Length); + } + + public static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress) + { + string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories); + int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1; + + using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress)) + foreach (string sFilePath in sFiles) + { + string sRelativePath = sFilePath.Substring(iDirLen); + if (progress != null) + progress(sRelativePath); + CompressFile(sInDir, sRelativePath, str); + } + } + + public static Stream DecompressFiletoStream(string fileName) { if (!File.Exists(fileName)) { - DebugConsole.ThrowError("File \""+fileName+" doesn't exist!"); + DebugConsole.ThrowError("File \"" + fileName + " doesn't exist!"); return null; } using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open)) { MemoryStream decompressedFileStream = new MemoryStream(); - + using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) { decompressionStream.CopyTo(decompressedFileStream); return decompressedFileStream; - } + } } } - + public static bool DecompressFile(string sDir, GZipStream zipStream, ProgressDelegate progress) { //Decompress file name @@ -75,12 +276,41 @@ namespace Barotrauma return true; } - + public static void DecompressToDirectory(string sCompressedFile, string sDir, ProgressDelegate progress) { using (FileStream inFile = new FileStream(sCompressedFile, FileMode.Open, FileAccess.Read, FileShare.None)) using (GZipStream zipStream = new GZipStream(inFile, CompressionMode.Decompress, true)) while (DecompressFile(sDir, zipStream, progress)) ; } + + private static void ClearFolder(string FolderName, string[] ignoredFiles = null) + { + DirectoryInfo dir = new DirectoryInfo(FolderName); + + foreach (FileInfo fi in dir.GetFiles()) + { + bool ignore = false; + foreach (string ignoredFile in ignoredFiles) + { + if (Path.GetFullPath(fi.FullName).Equals(Path.GetFullPath(ignoredFile))) + { + ignore = true; + break; + } + } + + if (ignore) continue; + + fi.IsReadOnly = false; + fi.Delete(); + } + + foreach (DirectoryInfo di in dir.GetDirectories()) + { + ClearFolder(di.FullName, ignoredFiles); + di.Delete(); + } + } } }