public void SavePlayers() { //refresh the character data of clients who are still in the server foreach (Client c in GameMain.Server.ConnectedClients) { //ignore if the character is controlling a monster //(we'll just use the previously saved campaign data if there's any) if (c.Character != null && c.Character.Info == null) { c.Character = null; } if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { //the client has opted to spawn this round with Reaper's Tax if (c.WaitForNextRoundRespawn.HasValue && !c.WaitForNextRoundRespawn.Value) { c.CharacterInfo.StartItemsGiven = false; characterData.RemoveAll(cd => cd.MatchesClient(c)); characterData.Add(new CharacterCampaignData(c, giveRespawnPenaltyAffliction: true)); continue; } } //use the info of the character the client is currently controlling // or the previously saved info if not (e.g. if the client has been spectating or died) var characterInfo = c.Character?.Info ?? characterData.Find(d => d.MatchesClient(c))?.CharacterInfo; if (characterInfo == null) { continue; } //reduce skills if the character has died if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { RespawnManager.ReduceCharacterSkills(characterInfo); } c.CharacterInfo = characterInfo; characterData.RemoveAll(cd => cd.MatchesClient(c)); characterData.Add(new CharacterCampaignData(c)); } //refresh the character data of clients who aren't in the server anymore List <CharacterCampaignData> prevCharacterData = new List <CharacterCampaignData>(characterData); foreach (CharacterCampaignData data in prevCharacterData) { if (data.HasSpawned && !GameMain.Server.ConnectedClients.Any(c => data.MatchesClient(c))) { var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk); if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected)) { characterData.RemoveAll(cd => cd.IsDuplicate(data)); data.Refresh(character); characterData.Add(data); } } } characterData.ForEach(cd => cd.HasSpawned = false); petsElement = new XElement("pets"); PetBehavior.SavePets(petsElement); //remove all items that are in someone's inventory foreach (Character c in Character.CharacterList) { if (c.Inventory == null) { continue; } if (Level.Loaded.Type == LevelData.LevelType.Outpost && c.Submarine != Level.Loaded.StartOutpost) { Map.CurrentLocation.RegisterTakenItems(c.Inventory.AllItems.Where(it => it.SpawnedInOutpost && it.OriginalModuleIndex > 0)); } if (c.Info != null && c.IsBot) { if (c.IsDead && c.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { CrewManager.RemoveCharacterInfo(c.Info); } c.Info.HealthData = new XElement("health"); c.CharacterHealth.Save(c.Info.HealthData); c.Info.InventoryData = new XElement("inventory"); c.SaveInventory(); c.Info.SaveOrderData(); } c.Inventory.DeleteAllItems(); } }