diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index 94fbf0e77..e5b69cf47 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -497,17 +497,22 @@ namespace Barotrauma { GameMain.Config.SettingsFrame.Draw(spriteBatch); } - + DebugConsole.Draw(spriteBatch); - + if (GUIComponent.MouseOn != null && !string.IsNullOrWhiteSpace(GUIComponent.MouseOn.ToolTip)) GUIComponent.MouseOn.DrawToolTip(spriteBatch); - + if (!GUI.DisableHUD) - cursor.Draw(spriteBatch, PlayerInput.LatestMousePosition); + cursor.Draw(spriteBatch, PlayerInput.LatestMousePosition); } public static void AddToGUIUpdateList() { + if (GUIMessageBox.VisibleBox != null) + { + GUIMessageBox.VisibleBox.AddToGUIUpdateList(); + } + if (pauseMenuOpen) { pauseMenu.AddToGUIUpdateList(); @@ -517,11 +522,6 @@ namespace Barotrauma { GameMain.Config.SettingsFrame.AddToGUIUpdateList(); } - - if (GUIMessageBox.VisibleBox != null) - { - GUIMessageBox.VisibleBox.AddToGUIUpdateList(); - } } public static void Update(float deltaTime) diff --git a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs index f90361ffc..d29d96b9b 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs @@ -11,8 +11,6 @@ namespace Barotrauma private static Texture2D iceCraters; private static Texture2D iceCrack; - public Action OnLocationSelected; - public void Update(float deltaTime, Rectangle rect, float scale = 1.0f) { Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs b/Barotrauma/BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs index c7e9109cd..a9e91230c 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/FileTransfer/FileReceiver.cs @@ -142,14 +142,18 @@ namespace Barotrauma.Networking private List activeTransfers; - private string downloadFolder; + private Dictionary downloadFolders = new Dictionary() + { + { FileTransferType.Submarine, "Submarines/Downloaded" }, + { FileTransferType.CampaignSave, "Data/Saves/Multiplayer" } + }; public List ActiveTransfers { get { return activeTransfers; } } - public FileReceiver(string downloadFolder) + public FileReceiver() { if (GameMain.Server != null) { @@ -157,8 +161,6 @@ namespace Barotrauma.Networking } activeTransfers = new List(); - - this.downloadFolder = downloadFolder; } public void ReadMessage(NetIncomingMessage inc) @@ -201,11 +203,13 @@ namespace Barotrauma.Networking if (GameSettings.VerboseLogging) { DebugConsole.Log("Received file transfer initiation message: "); - DebugConsole.Log(" File: "+fileName); + DebugConsole.Log(" File: " + fileName); DebugConsole.Log(" Size: " + fileSize); DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel); } + string downloadFolder = downloadFolders[(FileTransferType)fileType]; + if (!Directory.Exists(downloadFolder)) { try @@ -214,7 +218,7 @@ namespace Barotrauma.Networking } catch (Exception e) { - DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \""+downloadFolder+"\".", e); + DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \"" + downloadFolder + "\".", e); return; } } @@ -322,6 +326,13 @@ namespace Barotrauma.Networking return false; } break; + case (byte)FileTransferType.CampaignSave: + if (Path.GetExtension(fileName) != ".save") + { + errorMessage = "Wrong file extension ''" + Path.GetExtension(fileName) + "''! (Expected .save)"; + return false; + } + break; } return true; @@ -376,6 +387,9 @@ namespace Barotrauma.Networking stream.Close(); stream.Dispose(); break; + case FileTransferType.CampaignSave: + //TODO: verify that the received file is a valid save file + break; } return true; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 0b9c1aad8..d35f2f464 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -89,7 +89,7 @@ namespace Barotrauma.Networking entityEventManager = new ClientEntityEventManager(this); - fileReceiver = new FileReceiver("Submarines/Downloaded"); + fileReceiver = new FileReceiver(); fileReceiver.OnFinished += OnFileReceived; characterInfo = new CharacterInfo(Character.HumanConfigFile, name,Gender.None,null); @@ -703,8 +703,11 @@ namespace Barotrauma.Networking Rand.SetSyncedSeed(seed); - GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); - GameMain.GameSession.StartRound(levelSeed,loadSecondSub); + if (gameMode.Name != "Campaign") + { + GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); + } + GameMain.GameSession.StartRound(levelSeed, loadSecondSub); if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.SelectedShuttle); @@ -896,7 +899,16 @@ namespace Barotrauma.Networking Voting.AllowModeVoting = allowModeVoting; } } + + bool campaignUpdated = inc.ReadBoolean(); + inc.ReadPadBits(); + if (campaignUpdated) + { + MultiplayerCampaign.ClientRead(inc); + } + lastSentChatMsgID = inc.ReadUInt16(); + break; case ServerNetObject.CHAT_MESSAGE: ChatMessage.ClientRead(inc); @@ -961,6 +973,9 @@ namespace Barotrauma.Networking outmsg.Write(GameMain.NetLobbyScreen.LastUpdateID); outmsg.Write(ChatMessage.LastID); + var campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; + outmsg.Write(campaign == null ? 0 : campaign.LastUpdateID); + chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); for (int i = 0; i < chatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) { @@ -1038,8 +1053,8 @@ namespace Barotrauma.Networking msg.Write((byte)ClientPacketHeader.FILE_REQUEST); msg.Write((byte)FileTransferMessageType.Initiate); msg.Write((byte)fileType); - msg.Write(file); - msg.Write(fileHash); + if (file != null) msg.Write(file); + if (fileHash != null) msg.Write(fileHash); client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } @@ -1083,6 +1098,22 @@ namespace Barotrauma.Networking textBlock.UserData = newSub; textBlock.ToolTip = newSub.Description; } + break; + case FileTransferType.CampaignSave: + var campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; + if (campaign == null) return; + + GameMain.GameSession.SavePath = transfer.FilePath; + campaign.LastSaveID = campaign.PendingSaveID; + + if (GameMain.GameSession.Submarine == null) + { + var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath); + string subPath = Path.Combine(SaveUtil.TempPath, ToolBox.GetAttributeString(gameSessionDoc.Root, "submarine", "")) + ".sub"; + + GameMain.GameSession.Submarine = new Submarine(subPath, ""); + } + break; } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index b7a189647..9840dc18b 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -1,10 +1,7 @@ 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 @@ -18,6 +15,8 @@ namespace Barotrauma private GUITextBox saveNameBox, seedBox; + private GUIButton loadGameButton; + public Action StartNewGame; public Action LoadGame; @@ -138,8 +137,14 @@ namespace Barotrauma 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; }; + loadGameButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.Right | Alignment.Bottom, "", loadGameContainer); + loadGameButton.OnClicked = (btn, obj) => + { + if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) return false; + LoadGame?.Invoke(saveList.SelectedData as string); + return true; + }; + loadGameButton.Enabled = false; } private bool SelectSaveFile(GUIComponent component, object obj) @@ -154,6 +159,8 @@ namespace Barotrauma return false; } + loadGameButton.Enabled = true; + RemoveSaveFrame(); string subName = ToolBox.GetAttributeString(doc.Root, "submarine", ""); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index b58c0c412..985f6df06 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -1001,7 +1001,7 @@ namespace Barotrauma if (campaignContainer.Visible && campaignUI != null) { - campaignContainer.Update((float)deltaTime); + //campaignContainer.Update((float)deltaTime); campaignUI.Update((float)deltaTime); } @@ -1096,9 +1096,18 @@ namespace Barotrauma public void SelectMode(int modeIndex) { - modeList.Select(modeIndex, true); + if (modeIndex < 0 || modeIndex >= modeList.children.Count) return; - ToggleCampaignMode(SelectedMode.Name == "Campaign"); + if (GameMain.Server != null) + { + if (((GameModePreset)modeList.children[modeIndex].UserData).Name == "Campaign") + { + MultiplayerCampaign.StartCampaignSetup(); + return; + } + } + + modeList.Select(modeIndex, true); missionTypeBlock.Visible = SelectedMode != null && SelectedMode.Name == "Mission"; } @@ -1110,35 +1119,49 @@ namespace Barotrauma if (modePreset == null) return false; missionTypeBlock.Visible = modePreset.Name == "Mission"; - - if (modePreset.Name == "Campaign") + + if (GameMain.Server != null) { - MultiplayerCampaign.StartCampaignSetup(); - } - + //campaign selected and the campaign view has not been set up yet + // -> don't select the mode yet and start campaign setup + if (modePreset.Name == "Campaign" && !campaignContainer.Visible) + { + MultiplayerCampaign.StartCampaignSetup(); + return false; + } + } + lastUpdateID++; return true; } public void ToggleCampaignView(bool enabled) { - defaultModeContainer.Visible = !enabled; - StartButton.Visible = !enabled; - campaignContainer.Visible = enabled; + defaultModeContainer.Visible = !enabled; + if (StartButton != null) + { + StartButton.Visible = !enabled; + } } public void ToggleCampaignMode(bool enabled) { - StartButton.Visible = !enabled; - campaignViewButton.Visible = enabled; - ToggleCampaignView(enabled); - if (enabled && campaignUI == null) + if (enabled) { - campaignUI = new CampaignUI(GameMain.GameSession.GameMode as CampaignMode, campaignContainer); - campaignUI.StartRound = () => { GameMain.Server.StartGame(); }; + if (campaignUI == null) + { + campaignUI = new CampaignUI(GameMain.GameSession.GameMode as CampaignMode, campaignContainer); + campaignUI.StartRound = () => { GameMain.Server.StartGame(); }; + } + modeList.Select(2, true); + } + + if (GameMain.Server != null) + { + lastUpdateID++; } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs index 6d6b430fb..524ddbfde 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs @@ -1,14 +1,34 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Networking; +using Microsoft.Xna.Framework; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Xml.Linq; +using Lidgren.Network; +using System.Collections.Generic; namespace Barotrauma { class MultiplayerCampaign : CampaignMode { + private UInt16 lastUpdateID; + public UInt16 LastUpdateID + { + get { if (GameMain.Server != null && lastUpdateID < 1) lastUpdateID++; return lastUpdateID; } + set { lastUpdateID = value; } + } + + private UInt16 lastSaveID; + public UInt16 LastSaveID + { + get { if (GameMain.Server != null && lastSaveID < 1) lastSaveID++; return lastSaveID; } + set { lastSaveID = value; } + } + + public UInt16 PendingSaveID + { + get; + set; + } public MultiplayerCampaign(GameModePreset preset, object param) : base(preset, param) @@ -49,88 +69,123 @@ namespace Barotrauma GameMain.GameSession = new GameSession(sub, saveName, GameModePreset.list.Find(g => g.Name == "Campaign")); var campaign = ((MultiplayerCampaign)GameMain.GameSession.GameMode); campaign.GenerateMap(mapSeed); + campaign.map.OnLocationSelected += (loc, connection) => { campaign.LastUpdateID++; }; + setupBox.Close(); GameMain.NetLobbyScreen.ToggleCampaignMode(true); + + SaveUtil.SaveGame(GameMain.GameSession.SavePath); + campaign.LastSaveID++; }; campaignSetupUI.LoadGame = (string fileName) => { SaveUtil.LoadGame(fileName); + var campaign = ((MultiplayerCampaign)GameMain.GameSession.GameMode); + campaign.LastSaveID++; + setupBox.Close(); GameMain.NetLobbyScreen.ToggleCampaignMode(true); }; + + var cancelButton = new GUIButton(new Rectangle(0,0,120,30), "Cancel", Alignment.BottomLeft, "", setupBox.InnerFrame); + cancelButton.OnClicked += (btn, obj) => + { + setupBox.Close(); + int otherModeIndex = 0; + for (otherModeIndex = 0; otherModeIndex < GameMain.NetLobbyScreen.ModeList.children.Count; otherModeIndex++) + { + if (GameMain.NetLobbyScreen.ModeList.children[otherModeIndex].UserData is MultiplayerCampaign) continue; + break; + } + + GameMain.NetLobbyScreen.SelectMode(otherModeIndex); + return true; + }; } #endif + public override void Start() + { + base.Start(); + + lastUpdateID++; + } + 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 (GameMain.Server != null) { - if (subsToLeaveBehind == null || leavingSub == null) + lastUpdateID++; + + 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) { - 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) + if (subsToLeaveBehind == null || leavingSub == null) { - MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine); - LinkedSubmarine.CreateDummy(leavingSub, sub); + DebugConsole.ThrowError("Leaving submarine not selected -> selecting the closest one"); + + leavingSub = GetLeavingSub(); + + subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub); } }*/ - if (atEndPosition) + GameMain.GameSession.EndRound(""); + + if (success) { - Map.MoveToNextLocation(); + 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.SavePath); } - SaveUtil.SaveGame(GameMain.GameSession.SavePath); - } - - if (!success) - { - /* var summaryScreen = GUIMessageBox.VisibleBox; - - if (summaryScreen != null) + if (!success) { - summaryScreen = summaryScreen.children[0]; - summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton)); + /* var summaryScreen = GUIMessageBox.VisibleBox; - 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; }; + if (summaryScreen != null) + { + summaryScreen = summaryScreen.children[0]; + summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton)); - 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; }; - }*/ + 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--) @@ -165,6 +220,8 @@ namespace Barotrauma campaign.map.SetLocation(ToolBox.GetAttributeInt(element, "currentlocation", 0)); } + campaign.map.OnLocationSelected += (loc, connection) => { campaign.LastUpdateID++; }; + //campaign.savedOnStart = true; return campaign; } @@ -175,6 +232,73 @@ namespace Barotrauma modeElement.Add(new XAttribute("money", Money)); Map.Save(modeElement); element.Add(modeElement); + + lastSaveID++; } + + public void ServerWrite(NetBuffer msg, Client c) + { + System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue); + + msg.Write(lastUpdateID); + msg.Write(lastSaveID); + msg.Write(map.Seed); + msg.Write(map.CurrentLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.CurrentLocationIndex); + msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex); + + } + +#if CLIENT + public static void ClientRead(NetBuffer msg) + { + //static because we may need to instantiate the campaign if it hasn't been done yet + + UInt16 updateID = msg.ReadUInt16(); + UInt16 saveID = msg.ReadUInt16(); + string mapSeed = msg.ReadString(); + UInt16 currentLocIndex = msg.ReadUInt16(); + UInt16 selectedLocIndex = msg.ReadUInt16(); + + MultiplayerCampaign campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; + if (campaign == null) + { + string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer); + + GameMain.GameSession = new GameSession( + null, //TODO: set the sub (after receiving the save file?) + savePath, GameModePreset.list.Find(g => g.Name == "Campaign")); + + campaign = ((MultiplayerCampaign)GameMain.GameSession.GameMode); + campaign.GenerateMap(mapSeed); + + GameMain.NetLobbyScreen.ToggleCampaignMode(true); + } + if (NetIdUtils.IdMoreRecent(campaign.lastUpdateID, updateID)) return; + + //server has a newer save file + if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID)) + { + //stop any active campaign save transfers, they're outdated now + List saveTransfers = + GameMain.Client.FileReceiver.ActiveTransfers.FindAll(t => t.FileType == FileTransferType.CampaignSave); + + foreach (var transfer in saveTransfers) + { + GameMain.Client.FileReceiver.StopTransfer(transfer); + } + + GameMain.Client.RequestFile(FileTransferType.CampaignSave, null, null); + campaign.PendingSaveID = saveID; + } + //we've got the latest save file + else if (!NetIdUtils.IdMoreRecent(saveID, campaign.lastSaveID)) + { + campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex); + campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); + campaign.lastUpdateID = updateID; + } + } + +#endif } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index 419d27892..fe595e66b 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -79,6 +79,7 @@ namespace Barotrauma public string SavePath { get { return savePath; } + set { savePath = value; } } public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset = null, string missionType = "") @@ -168,7 +169,7 @@ namespace Barotrauma this.level = level; - if (submarine==null) + if (submarine == null) { DebugConsole.ThrowError("Couldn't start game session, submarine not selected"); return; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs index e57fe615d..bd6f9cf37 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs @@ -28,6 +28,8 @@ namespace Barotrauma private LocationConnection selectedConnection; + public Action OnLocationSelected; + public Location CurrentLocation { get { return currentLocation; } @@ -43,6 +45,11 @@ namespace Barotrauma get { return selectedLocation; } } + public int SelectedLocationIndex + { + get { return locations.IndexOf(selectedLocation); } + } + public LocationConnection SelectedConnection { get { return selectedConnection; } @@ -53,6 +60,11 @@ namespace Barotrauma get { return seed; } } + public List Locations + { + get { return locations; } + } + public static Map Load(XElement element) { string mapSeed = ToolBox.GetAttributeString(element, "seed", "a"); @@ -342,6 +354,12 @@ namespace Barotrauma public void SetLocation(int index) { + if (index == -1) + { + currentLocation = null; + return; + } + if (index < 0 || index >= locations.Count) { DebugConsole.ThrowError("Location index out of bounds"); @@ -352,6 +370,28 @@ namespace Barotrauma currentLocation.Discovered = true; } + public void SelectLocation(int index) + { + if (index == -1) + { + selectedLocation = null; + selectedConnection = null; + + OnLocationSelected?.Invoke(null, null); + return; + } + + if (index < 0 || index >= locations.Count) + { + DebugConsole.ThrowError("Location index out of bounds"); + return; + } + + selectedLocation = locations[index]; + selectedConnection = connections.Find(c => c.Locations.Contains(currentLocation) && c.Locations.Contains(selectedLocation)); + OnLocationSelected?.Invoke(selectedLocation, selectedConnection); + } + public void Save(XElement element) { XElement mapElement = new XElement("map"); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs index 8c7f62243..8289c2aff 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs @@ -36,7 +36,9 @@ namespace Barotrauma.Networking public UInt16 lastSentEntityEventID = 0; public UInt16 lastRecvEntityEventID = 0; - + + public UInt16 lastRecvCampaignUpdate = 0; + public List chatMsgQueue = new List(); public UInt16 lastChatMsgQueueID; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs b/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs index 6fd005a84..2d47499e4 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs @@ -18,7 +18,7 @@ namespace Barotrauma.Networking enum FileTransferType { - Submarine + Submarine, CampaignSave } class FileSender @@ -277,6 +277,12 @@ namespace Barotrauma.Networking StartTransfer(inc.SenderConnection, FileTransferType.Submarine, requestedSubmarine.FilePath); } break; + case (byte)FileTransferType.CampaignSave: + if (GameMain.GameSession != null) + { + StartTransfer(inc.SenderConnection, FileTransferType.CampaignSave, GameMain.GameSession.SavePath); + } + break; } } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 55b9c3298..bb41a1f42 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -611,6 +611,8 @@ namespace Barotrauma.Networking //TODO: might want to use a clever class for this c.lastRecvGeneralUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.lastRecvGeneralUpdate, GameMain.NetLobbyScreen.LastUpdateID); c.lastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.lastRecvChatMsgID, c.lastChatMsgQueueID); + + c.lastRecvCampaignUpdate = inc.ReadUInt16(); break; case ClientNetObject.CHAT_MESSAGE: ChatMessage.ServerRead(inc, c); @@ -964,6 +966,27 @@ namespace Barotrauma.Networking outmsg.Write(false); outmsg.WritePadBits(); } + + var campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; + if (campaign != null) + { + if (NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.lastRecvCampaignUpdate)) + { + outmsg.Write(true); + outmsg.WritePadBits(); + campaign.ServerWrite(outmsg, c); + } + else + { + outmsg.Write(false); + outmsg.WritePadBits(); + } + } + else + { + outmsg.Write(false); + outmsg.WritePadBits(); + } outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server @@ -1128,9 +1151,7 @@ namespace Barotrauma.Networking int teamCount = 1; byte hostTeam = 1; - - string levelSeed = GameMain.NetLobbyScreen.LevelSeed; - + MultiplayerCampaign campaign = GameMain.GameSession?.GameMode as MultiplayerCampaign; //don't instantiate a new gamesession if we're playing a campaign @@ -1310,7 +1331,7 @@ namespace Barotrauma.Networking msg.Write(seed); - msg.Write(GameMain.NetLobbyScreen.LevelSeed); + msg.Write(GameMain.GameSession.Level.Seed); msg.Write((byte)GameMain.NetLobbyScreen.MissionTypeIndex); diff --git a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs index 8365308fb..247fc0382 100644 --- a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs +++ b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs @@ -40,10 +40,19 @@ namespace Barotrauma try { - if (Submarine.MainSub != null && Submarine.Loaded.Contains(Submarine.MainSub)) + string subPath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub"); + if (Submarine.MainSub != null) { - Submarine.MainSub.FilePath = Path.Combine(tempPath, Submarine.MainSub.Name + ".sub"); - Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath); + if (Submarine.Loaded.Contains(Submarine.MainSub)) + { + Submarine.MainSub.FilePath = subPath; + Submarine.MainSub.SaveAs(Submarine.MainSub.FilePath); + } + else + { + File.Copy(Submarine.MainSub.FilePath, subPath); + Submarine.MainSub.FilePath = subPath; + } } } catch (Exception e) @@ -79,8 +88,8 @@ namespace Barotrauma 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); + Submarine selectedSub = new Submarine(subPath, ""); + GameMain.GameSession = new GameSession(selectedSub, filePath, doc); } public static XDocument LoadGameSessionDoc(string filePath)