private IEnumerable <Client> GetClientsToRespawn() { MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign; foreach (Client c in networkMember.ConnectedClients) { if (!c.InGame) { continue; } if (c.SpectateOnly && (GameMain.Server.ServerSettings.AllowSpectating || GameMain.Server.OwnerConnection == c.Connection)) { continue; } if (c.Character != null && !c.Character.IsDead) { continue; } //don't allow respawning if the client has previously disconnected and their corpse is still present on the server var matchingData = campaign?.GetClientCharacterData(c); if (matchingData != null && matchingData.HasSpawned && Character.CharacterList.Any(c => c.Info == matchingData.CharacterInfo && c.CauseOfDeath?.Type == CauseOfDeathType.Disconnected)) { continue; } yield return(c); } }
private IEnumerable <Client> GetClientsToRespawn() { MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign; foreach (Client c in networkMember.ConnectedClients) { if (!c.InGame) { continue; } if (c.SpectateOnly && (GameMain.Server.ServerSettings.AllowSpectating || GameMain.Server.OwnerConnection == c.Connection)) { continue; } if (c.Character != null && !c.Character.IsDead) { continue; } //don't allow respawn if the client already has a character (they'll regain control once they're in sync) var matchingData = campaign?.GetClientCharacterData(c); if (matchingData != null && matchingData.HasSpawned && Character.CharacterList.Any(c => c.Info == matchingData.CharacterInfo && !c.IsDead)) { continue; } if (UseRespawnPrompt) { if (matchingData != null && matchingData.HasSpawned) { if (!c.WaitForNextRoundRespawn.HasValue || c.WaitForNextRoundRespawn.Value) { continue; } } } yield return(c); } }
partial void RespawnCharactersProjSpecific() { var respawnSub = RespawnShuttle ?? Submarine.MainSub; MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign; var clients = GetClientsToRespawn().ToList(); foreach (Client c in clients) { //get rid of the existing character c.Character?.DespawnNow(); var matchingData = campaign?.GetClientCharacterData(c); if (matchingData != null && !matchingData.HasSpawned) { c.CharacterInfo = matchingData.CharacterInfo; } //all characters are in Team 1 in game modes/missions with only one team. //if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked c.TeamID = Character.TeamType.Team1; if (c.CharacterInfo == null) { c.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, c.Name); } } List <CharacterInfo> characterInfos = clients.Select(c => c.CharacterInfo).ToList(); var botsToSpawn = GetBotsToRespawn(); characterInfos.AddRange(botsToSpawn); GameMain.Server.AssignJobs(clients); foreach (Client c in clients) { if (campaign?.GetClientCharacterData(c) == null || c.CharacterInfo.Job == null) { c.CharacterInfo.Job = new Job(c.AssignedJob.First, c.AssignedJob.Second); } } //the spawnpoints where the characters will spawn var shuttleSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnSub); //the spawnpoints where they would spawn if they were spawned inside the main sub //(in order to give them appropriate ID card tags) var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); ItemPrefab divingSuitPrefab = MapEntityPrefab.Find(null, "divingsuit") as ItemPrefab; ItemPrefab oxyPrefab = MapEntityPrefab.Find(null, "oxygentank") as ItemPrefab; ItemPrefab scooterPrefab = MapEntityPrefab.Find(null, "underwaterscooter") as ItemPrefab; ItemPrefab batteryPrefab = MapEntityPrefab.Find(null, "batterycell") as ItemPrefab; var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo); for (int i = 0; i < characterInfos.Count; i++) { bool bot = i >= clients.Count; characterInfos[i].CurrentOrder = null; characterInfos[i].CurrentOrderOption = null; var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !bot, bot); character.TeamID = Character.TeamType.Team1; if (bot) { GameServer.Log(string.Format("Respawning bot {0} as {1}", character.Info.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } else { //tell the respawning client they're no longer a traitor if (GameMain.Server.TraitorManager?.Traitors != null && clients[i].Character != null) { if (GameMain.Server.TraitorManager.Traitors.Any(t => t.Character == clients[i].Character)) { GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("TraitorRespawnMessage"), clients[i], ChatMessageType.ServerMessageBox); } } clients[i].Character = character; character.OwnerClientEndPoint = clients[i].Connection.EndPointString; character.OwnerClientName = clients[i].Name; GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null) { Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position; if (divingSuitPrefab != null && oxyPrefab != null) { var divingSuit = new Item(divingSuitPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(divingSuit, false); respawnItems.Add(divingSuit); var oxyTank = new Item(oxyPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(oxyTank, false); divingSuit.Combine(oxyTank, user: null); respawnItems.Add(oxyTank); } if (scooterPrefab != null && batteryPrefab != null) { var scooter = new Item(scooterPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(scooter, false); var battery = new Item(batteryPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(battery, false); scooter.Combine(battery, user: null); respawnItems.Add(scooter); respawnItems.Add(battery); } } var characterData = campaign?.GetClientCharacterData(clients[i]); if (characterData == null || characterData.HasSpawned) { //give the character the items they would've gotten if they had spawned in the main sub character.GiveJobItems(mainSubSpawnPoints[i]); if (campaign != null) { characterData = campaign.SetClientCharacterData(clients[i]); characterData.HasSpawned = true; } } else { characterData.SpawnInventoryItems(character.Info, character.Inventory); characterData.ApplyHealthData(character.Info, character); character.GiveIdCardTags(mainSubSpawnPoints[i]); characterData.HasSpawned = true; } //add the ID card tags they should've gotten when spawning in the shuttle foreach (Item item in character.Inventory.Items) { if (item == null || item.Prefab.Identifier != "idcard") { continue; } foreach (string s in shuttleSpawnPoints[i].IdCardTags) { item.AddTag(s); } if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc)) { item.Description = shuttleSpawnPoints[i].IdCardDesc; } } } }
partial void RespawnCharactersProjSpecific(Vector2?shuttlePos) { respawnedCharacters.Clear(); var respawnSub = RespawnShuttle ?? Submarine.MainSub; MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign; var clients = GetClientsToRespawn().ToList(); foreach (Client c in clients) { //get rid of the existing character c.Character?.DespawnNow(); c.WaitForNextRoundRespawn = null; var matchingData = campaign?.GetClientCharacterData(c); if (matchingData != null && !matchingData.HasSpawned) { c.CharacterInfo = matchingData.CharacterInfo; } //all characters are in Team 1 in game modes/missions with only one team. //if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked c.TeamID = CharacterTeamType.Team1; if (c.CharacterInfo == null) { c.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, c.Name); } } List <CharacterInfo> characterInfos = clients.Select(c => c.CharacterInfo).ToList(); //bots don't respawn in the campaign if (campaign == null) { var botsToSpawn = GetBotsToRespawn(); characterInfos.AddRange(botsToSpawn); } GameMain.Server.AssignJobs(clients); foreach (Client c in clients) { if (campaign?.GetClientCharacterData(c) == null || c.CharacterInfo.Job == null) { c.CharacterInfo.Job = new Job(c.AssignedJob.First, c.AssignedJob.Second); } } //the spawnpoints where the characters will spawn var shuttleSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnSub); //the spawnpoints where they would spawn if they were spawned inside the main sub //(in order to give them appropriate ID card tags) var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); ItemPrefab divingSuitPrefab = null; if ((shuttlePos != null && Level.Loaded.GetRealWorldDepth(shuttlePos.Value.Y) > Level.DefaultRealWorldCrushDepth) || Level.Loaded.GetRealWorldDepth(Submarine.MainSub.WorldPosition.Y) > Level.DefaultRealWorldCrushDepth) { divingSuitPrefab = ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuitdeep", StringComparison.OrdinalIgnoreCase))); } if (divingSuitPrefab == null) { divingSuitPrefab = ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuit", StringComparison.OrdinalIgnoreCase))) ?? ItemPrefab.Find(null, "divingsuit"); } ItemPrefab oxyPrefab = ItemPrefab.Find(null, "oxygentank"); ItemPrefab scooterPrefab = ItemPrefab.Find(null, "underwaterscooter"); ItemPrefab batteryPrefab = ItemPrefab.Find(null, "batterycell"); var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo); for (int i = 0; i < characterInfos.Count; i++) { bool bot = i >= clients.Count; characterInfos[i].ClearCurrentOrders(); bool forceSpawnInMainSub = false; if (!bot && campaign != null) { var matchingData = campaign?.GetClientCharacterData(clients[i]); if (matchingData != null) { if (!matchingData.HasSpawned) { forceSpawnInMainSub = true; } else { ReduceCharacterSkills(characterInfos[i]); } } } var character = Character.Create(characterInfos[i], (forceSpawnInMainSub ? mainSubSpawnPoints[i] : shuttleSpawnPoints[i]).WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot); character.TeamID = CharacterTeamType.Team1; character.LoadTalents(); respawnedCharacters.Add(character); if (bot) { GameServer.Log(string.Format("Respawning bot {0} as {1}", character.Info.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } else { if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && character.Info != null) { character.Info.SetExperience(Math.Max(character.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(clients[i]))); mpCampaign.ClearSavedExperiencePoints(clients[i]); } //tell the respawning client they're no longer a traitor if (GameMain.Server.TraitorManager?.Traitors != null && clients[i].Character != null) { if (GameMain.Server.TraitorManager.Traitors.Any(t => t.Character == clients[i].Character)) { GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("TraitorRespawnMessage"), clients[i], ChatMessageType.ServerMessageBox); } } clients[i].Character = character; character.OwnerClientEndPoint = clients[i].Connection.EndPointString; character.OwnerClientName = clients[i].Name; GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning); } if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null) { Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position; if (divingSuitPrefab != null && oxyPrefab != null) { var divingSuit = new Item(divingSuitPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(divingSuit, false); respawnItems.Add(divingSuit); var oxyTank = new Item(oxyPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(oxyTank, false); divingSuit.Combine(oxyTank, user: null); respawnItems.Add(oxyTank); } if (scooterPrefab != null && batteryPrefab != null) { var scooter = new Item(scooterPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(scooter, false); var battery = new Item(batteryPrefab, pos, respawnSub); Spawner.CreateNetworkEvent(battery, false); scooter.Combine(battery, user: null); respawnItems.Add(scooter); respawnItems.Add(battery); } } var characterData = campaign?.GetClientCharacterData(clients[i]); if (characterData != null && Level.Loaded?.Type != LevelData.LevelType.Outpost && characterData.HasSpawned) { GiveRespawnPenaltyAffliction(character); } if (characterData == null || characterData.HasSpawned) { //give the character the items they would've gotten if they had spawned in the main sub character.GiveJobItems(mainSubSpawnPoints[i]); if (campaign != null) { characterData = campaign.SetClientCharacterData(clients[i]); characterData.HasSpawned = true; } } else { if (characterData.HasItemData) { characterData.SpawnInventoryItems(character, character.Inventory); } else { character.GiveJobItems(mainSubSpawnPoints[i]); } characterData.ApplyHealthData(character); character.GiveIdCardTags(mainSubSpawnPoints[i]); characterData.HasSpawned = true; } //add the ID card tags they should've gotten when spawning in the shuttle foreach (Item item in character.Inventory.AllItems.Distinct()) { if (item.Prefab.Identifier != "idcard") { continue; } foreach (string s in shuttleSpawnPoints[i].IdCardTags) { item.AddTag(s); } if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc)) { item.Description = shuttleSpawnPoints[i].IdCardDesc; } } } }