using Barotrauma.Networking; using Microsoft.Xna.Framework; using System; using System.Linq; using System.Xml.Linq; using Lidgren.Network; using System.Collections.Generic; using System.IO; namespace Barotrauma { partial class MultiPlayerCampaign : CampaignMode { private UInt16 lastUpdateID; public UInt16 LastUpdateID { get { #if SERVER if (GameMain.Server != null && lastUpdateID < 1) lastUpdateID++; #endif return lastUpdateID; } set { lastUpdateID = value; } } private UInt16 lastSaveID; public UInt16 LastSaveID { get { #if SERVER if (GameMain.Server != null && lastSaveID < 1) lastSaveID++; #endif return lastSaveID; } set { lastSaveID = value; } } public UInt16 PendingSaveID { get; set; } private static byte currentCampaignID; public byte CampaignID { get; private set; } public MultiPlayerCampaign(GameModePreset preset, object param) : base(preset, param) { currentCampaignID++; CampaignID = currentCampaignID; } public override void Start() { base.Start(); if (GameMain.NetworkMember.IsServer) lastUpdateID++; } public override void End(string endMessage = "") { isRunning = false; #if CLIENT if (GameMain.Client != null) { GameMain.GameSession.EndRound(""); GameMain.GameSession.CrewManager.EndRound(); return; } #endif #if SERVER lastUpdateID++; bool success = GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead); #if CLIENT success = success || (GameMain.Server.Character != null && !GameMain.Server.Character.IsDead); #endif /*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(""); foreach (Client c in GameMain.Server.ConnectedClients) { if (c.HasSpawned) { //client has spawned this round -> remove old data (and replace with new one if the client still has an alive character) characterData.RemoveAll(cd => cd.MatchesClient(c)); } if (c.Character?.Info != null && !c.Character.IsDead) { characterData.Add(new CharacterCampaignData(c)); } } //remove all items that are in someone's inventory foreach (Character c in Character.CharacterList) { c.Inventory?.DeleteAllItems(); } #if CLIENT GameMain.GameSession.CrewManager.EndRound(); #endif 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(); //select a random location to make sure we've got some destination //to head towards even if the host/clients don't select anything map.SelectRandomLocation(true); } map.ProgressWorld(); SaveUtil.SaveGame(GameMain.GameSession.SavePath); } #endif } partial void SetDelegates(); public static MultiPlayerCampaign LoadNew(XElement element) { MultiPlayerCampaign campaign = new MultiPlayerCampaign(GameModePreset.List.Find(gm => gm.Identifier == "multiplayercampaign"), null); campaign.Load(element); campaign.SetDelegates(); return campaign; } public static string GetCharacterDataSavePath(string savePath) { return Path.Combine(SaveUtil.MultiplayerSaveFolder, Path.GetFileNameWithoutExtension(savePath) + "_CharacterData.xml"); } public string GetCharacterDataSavePath() { return GetCharacterDataSavePath(GameMain.GameSession.SavePath); } public void Load(XElement element) { Money = element.GetAttributeInt("money", 0); CheatsEnabled = element.GetAttributeBool("cheatsenabled", false); if (CheatsEnabled) { DebugConsole.CheatsEnabled = true; if (GameMain.Config.UseSteam && !SteamAchievementManager.CheatsEnabled) { SteamAchievementManager.CheatsEnabled = true; #if CLIENT new GUIMessageBox("Cheats enabled", "Cheat commands have been enabled on the server. You will not receive Steam Achievements until you restart the game."); #else DebugConsole.NewMessage("Cheat commands have been enabled.", Color.Red); #endif } } foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "map": if (map == null) { //map not created yet, loading this campaign for the first time map = Map.LoadNew(subElement); } else { //map already created, update it //if we're not downloading the initial save file (LastSaveID > 0), //show notifications about location type changes map.Load(subElement, LastSaveID > 0); } break; } } #if SERVER characterData.Clear(); string characterDataPath = GetCharacterDataSavePath(); var characterDataDoc = XMLExtensions.TryLoadXml(characterDataPath); if (characterDataDoc?.Root == null) return; foreach (XElement subElement in characterDataDoc.Root.Elements()) { characterData.Add(new CharacterCampaignData(subElement)); } #endif } } }