v1.6.17.0 (Unto the Breach update)
This commit is contained in:
@@ -260,7 +260,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
Directory.CreateDirectory(downloadFolder, catchUnauthorizedAccessExceptions: false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -572,7 +572,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(transfer.FilePath);
|
||||
File.Delete(transfer.FilePath, catchUnauthorizedAccessExceptions: false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,11 @@ using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.PerkBehaviors;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -41,8 +43,9 @@ namespace Barotrauma.Networking
|
||||
nameId++;
|
||||
}
|
||||
|
||||
public void ForceNameAndJobUpdate()
|
||||
public void ForceNameJobTeamUpdate()
|
||||
{
|
||||
// Triggers SendLobbyUpdate() which causes the server to call GameServer.ClientReadLobby()
|
||||
nameId++;
|
||||
}
|
||||
|
||||
@@ -137,13 +140,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public Client MyClient => ConnectedClients.FirstOrDefault(c => c.SessionId == SessionId);
|
||||
|
||||
public Option<int> Ping
|
||||
{
|
||||
get
|
||||
{
|
||||
Client selfClient = ConnectedClients.FirstOrDefault(c => c.SessionId == SessionId);
|
||||
if (selfClient is null || selfClient.Ping == 0) { return Option<int>.None(); }
|
||||
return Option<int>.Some(selfClient.Ping);
|
||||
if (MyClient is null || MyClient.Ping == 0) { return Option<int>.None(); }
|
||||
return Option<int>.Some(MyClient.Ping);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,14 +489,13 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (VoipCapture.Instance.LastEnqueueAudio > DateTime.Now - new TimeSpan(0, 0, 0, 0, milliseconds: 100))
|
||||
{
|
||||
var myClient = ConnectedClients.Find(c => c.SessionId == SessionId);
|
||||
if (Screen.Selected == GameMain.NetLobbyScreen)
|
||||
{
|
||||
GameMain.NetLobbyScreen.SetPlayerSpeaking(myClient);
|
||||
GameMain.NetLobbyScreen.SetPlayerSpeaking(MyClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.SetClientSpeaking(myClient);
|
||||
GameMain.GameSession?.CrewManager?.SetClientSpeaking(MyClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -689,6 +692,16 @@ namespace Barotrauma.Networking
|
||||
string subName = inc.ReadString();
|
||||
string subHash = inc.ReadString();
|
||||
|
||||
bool hasEnemySub = inc.ReadBoolean();
|
||||
|
||||
string enemySubName = subName;
|
||||
string enemySubHash = subHash;
|
||||
if (hasEnemySub)
|
||||
{
|
||||
enemySubName = inc.ReadString();
|
||||
enemySubHash = inc.ReadString();
|
||||
}
|
||||
|
||||
bool usingShuttle = inc.ReadBoolean();
|
||||
string shuttleName = inc.ReadString();
|
||||
string shuttleHash = inc.ReadString();
|
||||
@@ -709,8 +722,13 @@ namespace Barotrauma.Networking
|
||||
bool readyToStart;
|
||||
if (campaign == null && campaignID == 0)
|
||||
{
|
||||
readyToStart = GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList) &&
|
||||
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
readyToStart = GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, SelectedSubType.Sub, GameMain.NetLobbyScreen.SubList) &&
|
||||
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, SelectedSubType.Shuttle, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
|
||||
if (hasEnemySub && !GameMain.NetLobbyScreen.TrySelectSub(enemySubName, enemySubHash, SelectedSubType.EnemySub, GameMain.NetLobbyScreen.SubList))
|
||||
{
|
||||
readyToStart = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -733,6 +751,19 @@ namespace Barotrauma.Networking
|
||||
CoroutineManager.StartCoroutine(NetLobbyScreen.WaitForStartRound(startButton: null), "WaitForStartRound");
|
||||
}
|
||||
break;
|
||||
case ServerPacketHeader.WARN_STARTGAME:
|
||||
DebugConsole.Log("Received WARN_STARTGAME packet.");
|
||||
|
||||
RoundStartWarningData warningData = INetSerializableStruct.Read<RoundStartWarningData>(inc);
|
||||
var team1IncompatiblePerks = ToolBox.UintIdentifierArrayToPrefabCollection(DisembarkPerkPrefab.Prefabs, warningData.Team1IncompatiblePerks);
|
||||
var team2IncompatiblePerks = ToolBox.UintIdentifierArrayToPrefabCollection(DisembarkPerkPrefab.Prefabs, warningData.Team2IncompatiblePerks);
|
||||
|
||||
GameMain.NetLobbyScreen?.ShowStartRoundWarning(SerializableDateTime.UtcNow + TimeSpan.FromSeconds(warningData.RoundStartsAnywaysTimeInSeconds), warningData.Team1Sub, team1IncompatiblePerks, warningData.Team2Sub, team2IncompatiblePerks);
|
||||
break;
|
||||
case ServerPacketHeader.CANCEL_STARTGAME:
|
||||
DebugConsole.Log("Received CANCEL_STARTGAME packet.");
|
||||
GameMain.NetLobbyScreen?.CloseStartRoundWarning();
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAME:
|
||||
DebugConsole.Log("Received STARTGAME packet.");
|
||||
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession?.GameMode is CampaignMode)
|
||||
@@ -869,6 +900,9 @@ namespace Barotrauma.Networking
|
||||
case ServerPacketHeader.EVENTACTION:
|
||||
GameMain.GameSession?.EventManager.ClientRead(inc);
|
||||
break;
|
||||
case ServerPacketHeader.SEND_BACKUP_INDICES:
|
||||
GameMain.NetLobbyScreen?.CampaignSetupUI?.OnBackupIndicesReceived(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -952,7 +986,7 @@ namespace Barotrauma.Networking
|
||||
", server value " + stage + ": " + levelEqualityCheckValues[stage].ToString("X") +
|
||||
", level value count: " + levelEqualityCheckValues.Count +
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||
", sub: " + (Submarine.MainSub == null ? "null" : (Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")")) +
|
||||
", mirrored: " + Level.Loaded.Mirrored + "). Round init status: " + roundInitStatus + "." + campaignErrorInfo;
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
@@ -969,9 +1003,24 @@ namespace Barotrauma.Networking
|
||||
CrewManager.ClientReadActiveOrders(inc);
|
||||
}
|
||||
|
||||
if (inc.ReadBoolean())
|
||||
{
|
||||
ApplyDisembarkPerk();
|
||||
}
|
||||
|
||||
roundInitStatus = RoundInitStatus.Started;
|
||||
}
|
||||
|
||||
private void ApplyDisembarkPerk()
|
||||
{
|
||||
var characters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
|
||||
ImmutableArray<Character> team1Characters = characters.Where(static c => c.TeamID is CharacterTeamType.Team1).ToImmutableArray(),
|
||||
team2Characters = characters.Where(static c => c.TeamID is CharacterTeamType.Team2).ToImmutableArray();
|
||||
|
||||
GameSession.GetPerks().ApplyAll(team1Characters, team2Characters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when the ClientPeer gets disconnected from the server. Does not necessarily mean the client is shutting down, we may still be able to reconnect.
|
||||
/// </summary>
|
||||
@@ -1396,6 +1445,7 @@ namespace Barotrauma.Networking
|
||||
ServerSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||
ServerSettings.AllowLinkingWifiToChat = inc.ReadBoolean();
|
||||
ServerSettings.MaximumMoneyTransferRequest = inc.ReadInt32();
|
||||
ServerSettings.RespawnMode = (RespawnMode)inc.ReadByte();
|
||||
bool usingShuttle = GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
GameMain.LightManager.LosMode = (LosMode)inc.ReadByte();
|
||||
ServerSettings.ShowEnemyHealthBars = (EnemyHealthBarMode)inc.ReadByte();
|
||||
@@ -1419,19 +1469,38 @@ namespace Barotrauma.Networking
|
||||
string subHash = inc.ReadString();
|
||||
string shuttleName = inc.ReadString();
|
||||
string shuttleHash = inc.ReadString();
|
||||
|
||||
bool hasEnemySub = inc.ReadBoolean();
|
||||
string enemySubName = subName;
|
||||
string enemySubHash = subHash;
|
||||
if (hasEnemySub)
|
||||
{
|
||||
enemySubName = inc.ReadString();
|
||||
enemySubHash = inc.ReadString();
|
||||
}
|
||||
|
||||
List<UInt32> missionHashes = new List<UInt32>();
|
||||
int missionCount = inc.ReadByte();
|
||||
for (int i = 0; i < missionCount; i++)
|
||||
{
|
||||
missionHashes.Add(inc.ReadUInt32());
|
||||
}
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList))
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, SelectedSubType.Sub, GameMain.NetLobbyScreen.SubList))
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox))
|
||||
if (hasEnemySub)
|
||||
{
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(enemySubName, enemySubHash, SelectedSubType.EnemySub, GameMain.NetLobbyScreen.SubList))
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, SelectedSubType.Shuttle, GameMain.NetLobbyScreen.ShuttleList.ListBox))
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Success;
|
||||
@@ -1480,8 +1549,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
var selectedMissions = missionHashes.Select(i => MissionPrefab.Prefabs.Find(p => p.UintIdentifier == i));
|
||||
|
||||
GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, gameMode, missionPrefabs: selectedMissions);
|
||||
GameMain.GameSession.StartRound(levelSeed, levelDifficulty);
|
||||
var selectedEnemySub = hasEnemySub && GameMain.NetLobbyScreen.SelectedEnemySub is { } enemySub ? Option.Some(enemySub) : Option.None;
|
||||
|
||||
GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, selectedEnemySub, gameMode, missionPrefabs: selectedMissions);
|
||||
GameMain.GameSession.StartRound(levelSeed, levelDifficulty, levelGenerationParams: null, forceBiome: ServerSettings.Biome);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1667,7 +1738,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession.Submarine.Info.IsFileCorrupted)
|
||||
if (GameMain.GameSession.Submarine != null &&
|
||||
GameMain.GameSession.Submarine.Info.IsFileCorrupted)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Info.Name}\".");
|
||||
yield return CoroutineStatus.Failure;
|
||||
@@ -1759,12 +1831,15 @@ namespace Barotrauma.Networking
|
||||
refSub = Submarine.MainSubs[1];
|
||||
}
|
||||
|
||||
// Enable characters near the main sub for the endCinematic
|
||||
foreach (Character c in Character.CharacterList)
|
||||
if (refSub != null)
|
||||
{
|
||||
if (Vector2.DistanceSquared(refSub.WorldPosition, c.WorldPosition) < MathUtils.Pow2(c.Params.DisableDistance))
|
||||
// Enable characters near the main sub for the endCinematic
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
c.Enabled = true;
|
||||
if (Vector2.DistanceSquared(refSub.WorldPosition, c.WorldPosition) < MathUtils.Pow2(c.Params.DisableDistance))
|
||||
{
|
||||
c.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1851,6 +1926,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
bool refreshCampaignUI = false;
|
||||
UInt16 listId = inc.ReadUInt16();
|
||||
GameMain.NetLobbyScreen.Team1Count = inc.ReadByte();
|
||||
GameMain.NetLobbyScreen.Team2Count = inc.ReadByte();
|
||||
List<TempClient> tempClients = new List<TempClient>();
|
||||
int clientCount = inc.ReadByte();
|
||||
for (int i = 0; i < clientCount; i++)
|
||||
@@ -1883,19 +1960,30 @@ namespace Barotrauma.Networking
|
||||
existingClient.NameId = tc.NameId;
|
||||
existingClient.PreferredJob = tc.PreferredJob;
|
||||
existingClient.PreferredTeam = tc.PreferredTeam;
|
||||
existingClient.TeamID = tc.TeamID;
|
||||
existingClient.Character = null;
|
||||
existingClient.Karma = tc.Karma;
|
||||
existingClient.Muted = tc.Muted;
|
||||
existingClient.InGame = tc.InGame;
|
||||
existingClient.IsOwner = tc.IsOwner;
|
||||
existingClient.IsDownloading = tc.IsDownloading;
|
||||
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
|
||||
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient); // refresh lobby player list in the local UI
|
||||
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterId > 0)
|
||||
{
|
||||
existingClient.CharacterID = tc.CharacterId;
|
||||
}
|
||||
if (existingClient.SessionId == SessionId)
|
||||
{
|
||||
MultiplayerPreferences.Instance.TeamPreference = existingClient.PreferredTeam;
|
||||
// If a team is already selected, make sure the UI reflects it
|
||||
if (MultiplayerPreferences.Instance.TeamPreference != CharacterTeamType.None)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TeamPreferenceListBox?.Select(MultiplayerPreferences.Instance.TeamPreference);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.NetLobbyScreen.RefreshPvpTeamSelectionButtons();
|
||||
}
|
||||
existingClient.SetPermissions(permissions, permittedConsoleCommands);
|
||||
if (!NetIdUtils.IdMoreRecent(nameId, tc.NameId))
|
||||
{
|
||||
@@ -1950,6 +2038,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
Steam.SteamManager.UpdateLobby(ServerSettings);
|
||||
}
|
||||
GameMain.NetLobbyScreen?.UpdateDisembarkPointListFromServerSettings();
|
||||
}
|
||||
|
||||
if (refreshCampaignUI)
|
||||
@@ -1960,6 +2049,7 @@ namespace Barotrauma.Networking
|
||||
campaign.CampaignUI?.HRManagerUI?.RefreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool initialUpdateReceived;
|
||||
@@ -1997,6 +2087,15 @@ namespace Barotrauma.Networking
|
||||
string selectSubName = inc.ReadString();
|
||||
string selectSubHash = inc.ReadString();
|
||||
|
||||
bool usingEnemySub = inc.ReadBoolean();
|
||||
string selectEnemySubName = selectSubName;
|
||||
string selectEnemySubHash = selectSubHash;
|
||||
if (usingEnemySub)
|
||||
{
|
||||
selectEnemySubName = inc.ReadString();
|
||||
selectEnemySubHash = inc.ReadString();
|
||||
}
|
||||
|
||||
bool usingShuttle = inc.ReadBoolean();
|
||||
string selectShuttleName = inc.ReadString();
|
||||
string selectShuttleHash = inc.ReadString();
|
||||
@@ -2011,7 +2110,13 @@ namespace Barotrauma.Networking
|
||||
float traitorProbability = inc.ReadSingle();
|
||||
int traitorDangerLevel = inc.ReadRangedInteger(TraitorEventPrefab.MinDangerLevel, TraitorEventPrefab.MaxDangerLevel);
|
||||
|
||||
MissionType missionType = (MissionType)inc.ReadRangedInteger(0, (int)MissionType.All);
|
||||
List<Identifier> missionTypes = new List<Identifier>();
|
||||
uint missionTypeCount = inc.ReadVariableUInt32();
|
||||
for (int i = 0; i < missionTypeCount; i++)
|
||||
{
|
||||
missionTypes.Add(inc.ReadIdentifier());
|
||||
}
|
||||
|
||||
int modeIndex = inc.ReadByte();
|
||||
|
||||
string levelSeed = inc.ReadString();
|
||||
@@ -2048,12 +2153,19 @@ namespace Barotrauma.Networking
|
||||
ServerSettings.ServerLog.ServerName = ServerSettings.ServerName;
|
||||
GameMain.NetLobbyScreen.UsingShuttle = usingShuttle;
|
||||
|
||||
if (!allowSubVoting || GameMain.NetLobbyScreen.SelectedSub == null) { GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, GameMain.NetLobbyScreen.SubList); }
|
||||
GameMain.NetLobbyScreen.TrySelectSub(selectShuttleName, selectShuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
if (!allowSubVoting || GameMain.NetLobbyScreen.SelectedSub == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, SelectedSubType.Sub, GameMain.NetLobbyScreen.SubList);
|
||||
if (usingEnemySub)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(selectEnemySubName, selectEnemySubHash, SelectedSubType.EnemySub, GameMain.NetLobbyScreen.SubList);
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen.TrySelectSub(selectShuttleName, selectShuttleHash, SelectedSubType.Shuttle, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
|
||||
GameMain.NetLobbyScreen.SetTraitorProbability(traitorProbability);
|
||||
GameMain.NetLobbyScreen.SetTraitorDangerLevel(traitorDangerLevel);
|
||||
GameMain.NetLobbyScreen.SetMissionType(missionType);
|
||||
GameMain.NetLobbyScreen.SetMissionTypes(missionTypes);
|
||||
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
|
||||
|
||||
GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
||||
@@ -2489,14 +2601,20 @@ namespace Barotrauma.Networking
|
||||
((SubmarineInfo)c.UserData).MD5Hash.StringRepresentation == newSub.MD5Hash.StringRepresentation);
|
||||
if (subElement == null) { continue; }
|
||||
|
||||
Color newSubTextColor = new Color(subElement.GetChild<GUITextBlock>().TextColor, 1.0f);
|
||||
subElement.GetChild<GUITextBlock>().TextColor = newSubTextColor;
|
||||
|
||||
if (subElement.GetChildByUserData("classtext") is GUITextBlock classTextBlock)
|
||||
//set the dimmed out submarine info back to normal and update texts
|
||||
if (subElement.FindChild("nametext", recursive: true) is GUITextBlock nameTextBlock)
|
||||
{
|
||||
nameTextBlock.TextColor = new Color(nameTextBlock.TextColor, 1.0f);
|
||||
}
|
||||
if (subElement.FindChild("classtext", recursive: true) is GUITextBlock classTextBlock)
|
||||
{
|
||||
Color newSubClassTextColor = new Color(classTextBlock.TextColor, 0.8f);
|
||||
classTextBlock.Text = TextManager.Get($"submarineclass.{newSub.SubmarineClass}");
|
||||
classTextBlock.TextColor = newSubClassTextColor;
|
||||
classTextBlock.TextColor = new Color(classTextBlock.TextColor, 0.8f);
|
||||
}
|
||||
if (subElement.FindChild("pricetext", recursive: true) is GUITextBlock priceTextBlock)
|
||||
{
|
||||
priceTextBlock.Text = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", newSub.Price));
|
||||
priceTextBlock.TextColor = new Color(priceTextBlock.TextColor, 0.8f);
|
||||
}
|
||||
|
||||
subElement.UserData = newSub;
|
||||
@@ -2507,14 +2625,22 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Name == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Hash == newSub.MD5Hash.StringRepresentation)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.StringRepresentation, GameMain.NetLobbyScreen.SubList);
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.StringRepresentation, SelectedSubType.Sub, GameMain.NetLobbyScreen.SubList);
|
||||
}
|
||||
|
||||
if (GameMain.NetLobbyScreen.FailedSelectedShuttle.HasValue &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Name == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Hash == newSub.MD5Hash.StringRepresentation)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.StringRepresentation, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.StringRepresentation, SelectedSubType.Shuttle, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
}
|
||||
|
||||
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.PvP &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedEnemySub.HasValue &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedEnemySub.Value.Name == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedEnemySub.Value.Hash == newSub.MD5Hash.StringRepresentation)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.StringRepresentation, SelectedSubType.EnemySub, GameMain.NetLobbyScreen.SubList);
|
||||
}
|
||||
|
||||
NetLobbyScreen.FailedSubInfo failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.StringRepresentation);
|
||||
@@ -2547,20 +2673,20 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.GameSession?.GameMode is not MultiPlayerCampaign campaign || campaign.CampaignID != campaignID)
|
||||
{
|
||||
string savePath = transfer.FilePath;
|
||||
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty);
|
||||
GameMain.GameSession = new GameSession(null, Option.None, CampaignDataPath.CreateRegular(savePath), GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty);
|
||||
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
|
||||
campaign.CampaignID = campaignID;
|
||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||
}
|
||||
|
||||
GameMain.GameSession.SavePath = transfer.FilePath;
|
||||
GameMain.GameSession.DataPath = CampaignDataPath.CreateRegular(transfer.FilePath);
|
||||
if (GameMain.GameSession.SubmarineInfo == null || campaign.Map == null)
|
||||
{
|
||||
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDocRoot.GetAttributeString("submarine", "")) + ".sub";
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
|
||||
}
|
||||
|
||||
campaign.LoadState(GameMain.GameSession.SavePath);
|
||||
campaign.LoadState(GameMain.GameSession.DataPath.LoadPath);
|
||||
GameMain.GameSession?.SubmarineInfo?.Reload();
|
||||
GameMain.GameSession?.SubmarineInfo?.CheckSubsLeftBehind();
|
||||
|
||||
@@ -2577,7 +2703,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
}
|
||||
|
||||
DebugConsole.Log("Campaign save received (" + GameMain.GameSession.SavePath + "), save ID " + campaign.LastSaveID);
|
||||
DebugConsole.Log("Campaign save received (" + GameMain.GameSession.DataPath + "), save ID " + campaign.LastSaveID);
|
||||
//decrement campaign update IDs so the server will send us the latest data
|
||||
//(as there may have been campaign updates after the save file was created)
|
||||
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
|
||||
@@ -2858,14 +2984,14 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Tell the server to select a submarine (permission required)
|
||||
/// </summary>
|
||||
public void RequestSelectSub(SubmarineInfo sub, bool isShuttle)
|
||||
public void RequestSelectSub(SubmarineInfo sub, SelectedSubType type)
|
||||
{
|
||||
if (!HasPermission(ClientPermissions.SelectSub) || sub == null) { return; }
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.WriteByte((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||
msg.WriteUInt16((UInt16)ClientPermissions.SelectSub);
|
||||
msg.WriteBoolean(isShuttle); msg.WritePadBits();
|
||||
msg.WriteUInt16((ushort)ClientPermissions.SelectSub);
|
||||
msg.WriteByte((byte)type);
|
||||
msg.WriteString(sub.MD5Hash.StringRepresentation);
|
||||
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
@@ -2909,7 +3035,7 @@ namespace Barotrauma.Networking
|
||||
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void SetupLoadCampaign(string saveName)
|
||||
public void SetupLoadCampaign(string filePath, Option<uint> backupIndex)
|
||||
{
|
||||
if (ClientPeer == null) { return; }
|
||||
|
||||
@@ -2920,7 +3046,19 @@ namespace Barotrauma.Networking
|
||||
msg.WriteByte((byte)ClientPacketHeader.CAMPAIGN_SETUP_INFO);
|
||||
|
||||
msg.WriteBoolean(false); msg.WritePadBits();
|
||||
msg.WriteString(saveName);
|
||||
msg.WriteString(filePath);
|
||||
|
||||
if (backupIndex.TryUnwrap(out uint index))
|
||||
{
|
||||
msg.WriteBoolean(true);
|
||||
msg.WritePadBits();
|
||||
msg.WriteUInt32(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.WriteBoolean(false);
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
@@ -3062,7 +3200,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool EnterChatMessage(GUITextBox textBox, string message)
|
||||
{
|
||||
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
|
||||
var messageType = NetLobbyScreen.TeamChatSelected ? ChatMessageType.Team : ChatMessageType.Default;
|
||||
textBox.TextColor = ChatMessage.MessageColor[(int)messageType];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
@@ -3070,7 +3209,7 @@ namespace Barotrauma.Networking
|
||||
return false;
|
||||
}
|
||||
chatBox.ChatManager.Store(message);
|
||||
SendChatMessage(message);
|
||||
SendChatMessage(message, type: messageType);
|
||||
|
||||
if (textBox.DeselectAfterMessage)
|
||||
{
|
||||
@@ -3559,9 +3698,9 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
|
||||
}
|
||||
if (GameMain.NetworkMember?.RespawnManager?.RespawnShuttle != null)
|
||||
if (GameMain.NetworkMember?.RespawnManager is { } respawnManager)
|
||||
{
|
||||
errorLines.Add("Respawn shuttle: " + GameMain.NetworkMember.RespawnManager.RespawnShuttle.Info.Name);
|
||||
errorLines.Add("Respawn shuttles: " + string.Join(", ", respawnManager.RespawnShuttles.Select(s => s.Info.Name)));
|
||||
}
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool AllowModDownloads { get; private set; } = true;
|
||||
|
||||
public string AutomaticallyAttemptedPassword = string.Empty;
|
||||
|
||||
public readonly record struct Callbacks(
|
||||
Callbacks.MessageCallback OnMessageReceived,
|
||||
Callbacks.DisconnectCallback OnDisconnect,
|
||||
@@ -102,8 +104,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
TaskPool.Add($"{GetType().Name}.{nameof(GetAccountId)}", GetAccountId(), t =>
|
||||
{
|
||||
if (GameMain.Client?.ClientPeer is null) { return; }
|
||||
|
||||
// FIXME what to do with this?
|
||||
//if (GameMain.Client?.ClientPeer is null) { return; }
|
||||
|
||||
if (!t.TryGetResult(out Option<AccountId> accountId))
|
||||
{
|
||||
Close(PeerDisconnectPacket.WithReason(DisconnectReason.AuthenticationFailed));
|
||||
@@ -118,7 +121,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
var body = new ClientAuthTicketAndVersionPacket
|
||||
{
|
||||
Name = GameMain.Client.Name,
|
||||
Name = GameMain.Client?.Name ?? "Unknown",
|
||||
OwnerKey = ownerKey,
|
||||
AccountId = accountId,
|
||||
AuthTicket = authTicket,
|
||||
@@ -177,10 +180,16 @@ namespace Barotrauma.Networking
|
||||
var passwordPacket = INetSerializableStruct.Read<ServerPeerPasswordPacket>(inc.Message);
|
||||
|
||||
if (WaitingForPassword) { return; }
|
||||
|
||||
|
||||
passwordPacket.Salt.TryUnwrap(out passwordSalt);
|
||||
passwordPacket.RetriesLeft.TryUnwrap(out var retries);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(AutomaticallyAttemptedPassword))
|
||||
{
|
||||
SendPassword(AutomaticallyAttemptedPassword);
|
||||
return;
|
||||
}
|
||||
|
||||
LocalizedString pwMsg = TextManager.Get("PasswordRequired");
|
||||
|
||||
passwordMsgBox?.Close();
|
||||
|
||||
+7
-4
@@ -224,10 +224,13 @@ namespace Barotrauma.Networking
|
||||
ToolBox.ThrowIfNull(netPeerConfiguration);
|
||||
|
||||
#if DEBUG
|
||||
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Client.SimulatedDuplicatesChance;
|
||||
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Client.SimulatedMinimumLatency;
|
||||
netPeerConfiguration.SimulatedRandomLatency = GameMain.Client.SimulatedRandomLatency;
|
||||
netPeerConfiguration.SimulatedLoss = GameMain.Client.SimulatedLoss;
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Client.SimulatedDuplicatesChance;
|
||||
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Client.SimulatedMinimumLatency;
|
||||
netPeerConfiguration.SimulatedRandomLatency = GameMain.Client.SimulatedRandomLatency;
|
||||
netPeerConfiguration.SimulatedLoss = GameMain.Client.SimulatedLoss;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte[] bufAux = msg.PrepareForSending(compressPastThreshold, out bool isCompressed, out _);
|
||||
|
||||
@@ -22,6 +22,12 @@ namespace Barotrauma.Networking
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public DateTime ReturnTime { get; private set; }
|
||||
public DateTime RespawnTime { get; private set; }
|
||||
public State CurrentState { get; private set; }
|
||||
public bool ReturnCountdownStarted { get; private set; }
|
||||
public bool RespawnCountdownStarted { get; private set; }
|
||||
|
||||
public static void ShowDeathPromptIfNeeded(float delay = 1.0f)
|
||||
{
|
||||
if (UseDeathPrompt)
|
||||
@@ -30,13 +36,18 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateTransportingProjSpecific(float deltaTime)
|
||||
partial void UpdateTransportingProjSpecific(TeamSpecificState teamSpecificState, float deltaTime)
|
||||
{
|
||||
if (GameMain.Client?.Character == null || GameMain.Client.Character.Submarine != RespawnShuttle) { return; }
|
||||
if (!ReturnCountdownStarted) { return; }
|
||||
if (GameMain.Client?.Character == null ||
|
||||
GameMain.Client.Character.Submarine is not { IsRespawnShuttle: true } ||
|
||||
GameMain.Client.Character.TeamID != teamSpecificState.TeamID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!teamSpecificState.ReturnCountdownStarted) { return; }
|
||||
|
||||
//show a warning when there's 20 seconds until the shuttle leaves
|
||||
if ((ReturnTime - DateTime.Now).TotalSeconds < 20.0f &&
|
||||
if ((teamSpecificState.ReturnTime - DateTime.Now).TotalSeconds < 20.0f &&
|
||||
(DateTime.Now - lastShuttleLeavingWarningTime).TotalSeconds > 30.0f)
|
||||
{
|
||||
lastShuttleLeavingWarningTime = DateTime.Now;
|
||||
@@ -46,43 +57,56 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void ClientEventRead(IReadMessage msg, float sendingTime)
|
||||
{
|
||||
bool respawnPromptPending = false;
|
||||
var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length);
|
||||
switch (newState)
|
||||
var myTeamId = (CharacterTeamType)msg.ReadByte();
|
||||
foreach (var teamSpecificState in teamSpecificStates.Values)
|
||||
{
|
||||
case State.Transporting:
|
||||
ReturnCountdownStarted = msg.ReadBoolean();
|
||||
maxTransportTime = msg.ReadSingle();
|
||||
float transportTimeLeft = msg.ReadSingle();
|
||||
var teamId = (CharacterTeamType)msg.ReadByte();
|
||||
|
||||
ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(transportTimeLeft * 1000.0f));
|
||||
RespawnCountdownStarted = false;
|
||||
if (CurrentState != newState)
|
||||
{
|
||||
CoroutineManager.StopCoroutines("forcepos");
|
||||
}
|
||||
break;
|
||||
case State.Waiting:
|
||||
PendingRespawnCount = msg.ReadUInt16();
|
||||
RequiredRespawnCount = msg.ReadUInt16();
|
||||
respawnPromptPending = msg.ReadBoolean();
|
||||
RespawnCountdownStarted = msg.ReadBoolean();
|
||||
ResetShuttle();
|
||||
float newRespawnTime = msg.ReadSingle();
|
||||
RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(newRespawnTime * 1000.0f));
|
||||
break;
|
||||
case State.Returning:
|
||||
RespawnCountdownStarted = false;
|
||||
break;
|
||||
bool respawnPromptPending = false;
|
||||
var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length);
|
||||
switch (newState)
|
||||
{
|
||||
case State.Transporting:
|
||||
teamSpecificState.ReturnCountdownStarted = msg.ReadBoolean();
|
||||
maxTransportTime = msg.ReadSingle();
|
||||
float transportTimeLeft = msg.ReadSingle();
|
||||
|
||||
teamSpecificState.ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(transportTimeLeft * 1000.0f));
|
||||
teamSpecificState.RespawnCountdownStarted = false;
|
||||
break;
|
||||
case State.Waiting:
|
||||
teamSpecificState.PendingRespawnCount = msg.ReadUInt16();
|
||||
teamSpecificState.RequiredRespawnCount = msg.ReadUInt16();
|
||||
respawnPromptPending = msg.ReadBoolean();
|
||||
teamSpecificState.RespawnCountdownStarted = msg.ReadBoolean();
|
||||
ResetShuttle(teamSpecificState);
|
||||
float newRespawnTime = msg.ReadSingle();
|
||||
teamSpecificState.RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(newRespawnTime * 1000.0f));
|
||||
break;
|
||||
case State.Returning:
|
||||
teamSpecificState.RespawnCountdownStarted = false;
|
||||
break;
|
||||
}
|
||||
teamSpecificState.CurrentState = newState;
|
||||
|
||||
if (respawnPromptPending)
|
||||
{
|
||||
GameMain.Client.HasSpawned = true;
|
||||
DeathPrompt.Create(delay: 1.0f);
|
||||
}
|
||||
|
||||
if (teamId == myTeamId)
|
||||
{
|
||||
PendingRespawnCount = teamSpecificState.PendingRespawnCount;
|
||||
RequiredRespawnCount = teamSpecificState.RequiredRespawnCount;
|
||||
ReturnTime = teamSpecificState.ReturnTime;
|
||||
RespawnTime = teamSpecificState.RespawnTime;
|
||||
CurrentState = teamSpecificState.CurrentState;
|
||||
ReturnCountdownStarted = teamSpecificState.ReturnCountdownStarted;
|
||||
RespawnCountdownStarted = teamSpecificState.RespawnCountdownStarted;
|
||||
}
|
||||
}
|
||||
CurrentState = newState;
|
||||
|
||||
if (respawnPromptPending)
|
||||
{
|
||||
GameMain.Client.HasSpawned = true;
|
||||
DeathPrompt.Create(delay: 1.0f);
|
||||
}
|
||||
|
||||
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,9 +144,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
var pingLocation = NetPingLocation.TryParseFromString(pingLocationStr);
|
||||
|
||||
if (pingLocation.HasValue && Steamworks.SteamNetworkingUtils.LocalPingLocation.HasValue)
|
||||
if (pingLocation.HasValue)
|
||||
{
|
||||
int ping = Steamworks.SteamNetworkingUtils.LocalPingLocation.Value.EstimatePingTo(pingLocation.Value);
|
||||
int ping = Steamworks.SteamNetworkingUtils.EstimatePingTo(pingLocation.Value);
|
||||
if (ping < 0) { return Result.Failure(SteamLobbyPingError.PingEstimationFailed); }
|
||||
return Result.Success(ping);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
@@ -178,6 +179,11 @@ namespace Barotrauma.Networking
|
||||
extraCargoPanel.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReadPerks(incMsg))
|
||||
{
|
||||
GameMain.NetLobbyScreen?.UpdateDisembarkPointListFromServerSettings();
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.HiddenSubs))
|
||||
@@ -194,10 +200,41 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasPermissionToChangePerks()
|
||||
{
|
||||
if (GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) { return true; }
|
||||
|
||||
bool isPvP = GameMain.NetLobbyScreen?.SelectedMode == GameModePreset.PvP;
|
||||
bool hasSelectedTeam = MultiplayerPreferences.Instance.TeamPreference is CharacterTeamType.Team1 or CharacterTeamType.Team2;
|
||||
var otherClients = GameMain.Client?.ConnectedClients.Where(static c => c.SessionId != GameMain.Client.SessionId).ToImmutableArray() ?? ImmutableArray<Client>.Empty;
|
||||
|
||||
if (isPvP)
|
||||
{
|
||||
if (!hasSelectedTeam) { return false; }
|
||||
|
||||
return !otherClients
|
||||
.Where(static c => c.PreferredTeam == MultiplayerPreferences.Instance.TeamPreference)
|
||||
.Any(static c => c.HasPermission(Networking.ClientPermissions.ManageSettings));
|
||||
}
|
||||
else
|
||||
{
|
||||
return !otherClients.Any(static c => c.HasPermission(Networking.ClientPermissions.ManageSettings));
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminWritePerks()
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
|
||||
outMsg.WriteByte((byte)ClientPacketHeader.SERVER_SETTINGS_PERKS);
|
||||
WritePerks(outMsg);
|
||||
GameMain.Client?.ClientPeer?.Send(outMsg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public void ClientAdminWrite(
|
||||
NetFlags dataToSend,
|
||||
int? missionTypeOr = null,
|
||||
int? missionTypeAnd = null,
|
||||
Identifier addedMissionType = default,
|
||||
Identifier removedMissionType = default,
|
||||
int traitorDangerLevel = 0)
|
||||
{
|
||||
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) { return; }
|
||||
@@ -220,7 +257,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.WriteUInt32(count);
|
||||
foreach (KeyValuePair<UInt32, NetPropertyData> prop in changedProperties)
|
||||
{
|
||||
DebugConsole.NewMessage(prop.Value.Name.Value, Color.Lime);
|
||||
DebugConsole.NewMessage($"Changed {prop.Value.Name.Value} to {prop.Value.GUIComponentValue}", Color.Lime);
|
||||
outMsg.WriteUInt32(prop.Key);
|
||||
prop.Value.Write(outMsg, prop.Value.GUIComponentValue);
|
||||
}
|
||||
@@ -237,8 +274,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (dataToSend.HasFlag(NetFlags.Misc))
|
||||
{
|
||||
outMsg.WriteRangedInteger(missionTypeOr ?? (int)Barotrauma.MissionType.None, 0, (int)Barotrauma.MissionType.All);
|
||||
outMsg.WriteRangedInteger(missionTypeAnd ?? (int)Barotrauma.MissionType.All, 0, (int)Barotrauma.MissionType.All);
|
||||
outMsg.WriteIdentifier(addedMissionType);
|
||||
outMsg.WriteIdentifier(removedMissionType);
|
||||
outMsg.WriteByte((byte)(traitorDangerLevel + 1));
|
||||
outMsg.WritePadBits();
|
||||
}
|
||||
|
||||
@@ -418,8 +418,44 @@ namespace Barotrauma.Networking
|
||||
var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
|
||||
AssignGUIComponent(nameof(RandomizeSeed), randomizeLevelBox);
|
||||
|
||||
//***********************************************
|
||||
|
||||
// ******* PVP ********************************
|
||||
NetLobbyScreen.CreateSubHeader("gamemode.pvp", listBox.Content);
|
||||
|
||||
var teamSelectModeLabel = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1.0f, 0.05f),
|
||||
listBox.Content.RectTransform),
|
||||
TextManager.Get("TeamSelectionMode"));
|
||||
teamSelectModeLabel.ToolTip = TextManager.Get("TeamSelectionMode.tooltip");
|
||||
var teamSelectionMode = new GUISelectionCarousel<PvpTeamSelectionMode>(
|
||||
new RectTransform(new Vector2(0.5f, 0.6f),
|
||||
teamSelectModeLabel.RectTransform,
|
||||
Anchor.CenterRight));
|
||||
foreach (PvpTeamSelectionMode teamSelectionModeOption in Enum.GetValues(typeof(PvpTeamSelectionMode)))
|
||||
{
|
||||
var optionName = teamSelectionModeOption.ToString();
|
||||
teamSelectionMode.AddElement(teamSelectionModeOption,
|
||||
TextManager.Get($"TeamSelectionMode.{optionName}"),
|
||||
TextManager.Get($"TeamSelectionMode.{optionName}.tooltip"));
|
||||
}
|
||||
AssignGUIComponent(nameof(PvpTeamSelectionMode), teamSelectionMode);
|
||||
|
||||
var autoBalanceThresholdLabel = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1.0f, 0.05f),
|
||||
listBox.Content.RectTransform),
|
||||
TextManager.Get("AutoBalanceThreshold"));
|
||||
var autoBalanceThresholdTooltip = TextManager.Get("AutoBalanceThreshold.tooltip");
|
||||
autoBalanceThresholdLabel.ToolTip = autoBalanceThresholdTooltip;
|
||||
var autoBalanceThreshold = new GUISelectionCarousel<int>(
|
||||
new RectTransform(new Vector2(0.5f, 0.6f),
|
||||
autoBalanceThresholdLabel.RectTransform,
|
||||
Anchor.CenterRight));
|
||||
autoBalanceThreshold.AddElement(0, TextManager.Get($"AutoBalanceThreshold.Off"), autoBalanceThresholdTooltip);
|
||||
autoBalanceThreshold.AddElement(1, "1", autoBalanceThresholdTooltip);
|
||||
autoBalanceThreshold.AddElement(2, "2", autoBalanceThresholdTooltip);
|
||||
autoBalanceThreshold.AddElement(3, "3", autoBalanceThresholdTooltip);
|
||||
AssignGUIComponent(nameof(PvpAutoBalanceThreshold), autoBalanceThreshold);
|
||||
|
||||
// ******* GAMEPLAY ***************************
|
||||
NetLobbyScreen.CreateSubHeader("serversettingsroundstab", listBox.Content);
|
||||
|
||||
var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
|
||||
@@ -485,6 +521,9 @@ namespace Barotrauma.Networking
|
||||
AssignGUIComponent(nameof(NewCampaignDefaultSalary), defaultSalarySlider);
|
||||
defaultSalarySlider.OnMoved(defaultSalarySlider, defaultSalarySlider.BarScroll);
|
||||
|
||||
var pvpDisembarkPoints = NetLobbyScreen.CreateLabeledNumberInput(listBox.Content, "serversettingsdisembarkpoints", 0, 100, "serversettingsdisembarkpointstooltip");
|
||||
AssignGUIComponent(nameof(DisembarkPointAllowance), pvpDisembarkPoints);
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// game settings
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
@@ -320,7 +320,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
private Sound overrideSound;
|
||||
private int overridePos;
|
||||
private short[] overrideBuf = new short[VoipConfig.BUFFER_SIZE];
|
||||
private readonly short[] overrideBuf = new short[VoipConfig.BUFFER_SIZE];
|
||||
|
||||
private void FillBuffer()
|
||||
{
|
||||
@@ -331,13 +331,13 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
int sampleCount = overrideSound.FillStreamBuffer(overridePos, overrideBuf);
|
||||
overridePos += sampleCount * 2;
|
||||
Array.Copy(overrideBuf, 0, uncompressedBuffer, totalSampleCount, sampleCount);
|
||||
Array.Copy(overrideBuf, 0, uncompressedBuffer, totalSampleCount, Math.Min(sampleCount, uncompressedBuffer.Length - totalSampleCount));
|
||||
totalSampleCount += sampleCount;
|
||||
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
overridePos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int sleepMs = VoipConfig.BUFFER_SIZE * 800 / VoipConfig.FREQUENCY;
|
||||
Thread.Sleep(sleepMs - 1);
|
||||
@@ -382,7 +382,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
overrideSound = GameMain.SoundManager.LoadSound(fileName, true);
|
||||
try
|
||||
{
|
||||
overrideSound = GameMain.SoundManager.LoadSound(fileName, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to load the sound {fileName}.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,22 +59,77 @@ namespace Barotrauma
|
||||
switch (voteType)
|
||||
{
|
||||
case VoteType.Sub:
|
||||
case VoteType.Mode:
|
||||
GUIListBox listBox = (voteType == VoteType.Sub) ?
|
||||
GameMain.NetLobbyScreen.SubList : GameMain.NetLobbyScreen.ModeList;
|
||||
var subList = GameMain.NetLobbyScreen.SubList;
|
||||
|
||||
foreach (GUIComponent comp in listBox.Content.Children)
|
||||
foreach (GUIComponent comp in subList.Content.Children)
|
||||
{
|
||||
if (comp.FindChild("votes") is GUITextBlock voteText) { comp.RemoveChild(voteText); }
|
||||
TryRemoveVoteText(comp);
|
||||
|
||||
var container = comp.GetChild<GUILayoutGroup>();
|
||||
var imageFrame = container.GetChild<GUIFrame>();
|
||||
var coalIcon = imageFrame.GetChildByUserData(NetLobbyScreen.CoalitionIconUserData);
|
||||
var sepIcon = imageFrame.GetChildByUserData(NetLobbyScreen.SeparatistsIconUserData);
|
||||
|
||||
coalIcon.Enabled = false;
|
||||
sepIcon.Enabled = false;
|
||||
|
||||
TryRemoveVoteText(coalIcon);
|
||||
TryRemoveVoteText(sepIcon);
|
||||
|
||||
static void TryRemoveVoteText(GUIComponent component)
|
||||
{
|
||||
if (component.FindChild("votes") is GUITextBlock foundText)
|
||||
{
|
||||
component.RemoveChild(foundText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clients == null) { return; }
|
||||
|
||||
IReadOnlyDictionary<object, int> voteList = GetVoteCounts<object>(voteType, clients);
|
||||
foreach (KeyValuePair<object, int> votable in voteList)
|
||||
|
||||
bool isPvP = GameMain.NetLobbyScreen?.SelectedMode == GameModePreset.PvP;
|
||||
|
||||
if (isPvP)
|
||||
{
|
||||
SetVoteText(listBox, votable.Key, votable.Value);
|
||||
}
|
||||
var coalitionVoteList = GetVoteCounts<SubmarineInfo>(voteType, clients.Where(static c => c.PreferredTeam is CharacterTeamType.Team1));
|
||||
var separatistVoteList = GetVoteCounts<SubmarineInfo>(voteType, clients.Where(static c => c.PreferredTeam is CharacterTeamType.Team2));
|
||||
foreach (var (subInfo, amount) in coalitionVoteList)
|
||||
{
|
||||
SetSubVoteText(subList, subInfo, amount, CharacterTeamType.Team1);
|
||||
}
|
||||
|
||||
foreach (var (subInfo, amount) in separatistVoteList)
|
||||
{
|
||||
SetSubVoteText(subList, subInfo, amount, CharacterTeamType.Team2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var subVoteList = GetVoteCounts<SubmarineInfo>(voteType, clients);
|
||||
foreach (var (subInfo, amount) in subVoteList)
|
||||
{
|
||||
SetSubVoteText(subList, subInfo, amount, CharacterTeamType.None);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case VoteType.Mode:
|
||||
var modeList = GameMain.NetLobbyScreen.ModeList;
|
||||
foreach (GUIComponent comp in modeList.Content.Children)
|
||||
{
|
||||
if (comp.FindChild("votes") is GUITextBlock voteText)
|
||||
{
|
||||
comp.RemoveChild(voteText);
|
||||
}
|
||||
}
|
||||
|
||||
if (clients == null) { return; }
|
||||
|
||||
var modeVoteList = GetVoteCounts<GameModePreset>(voteType, clients);
|
||||
foreach (var (preset, amount) in modeVoteList)
|
||||
{
|
||||
SetVoteText(modeList, preset, amount);
|
||||
}
|
||||
break;
|
||||
case VoteType.StartRound:
|
||||
if (clients == null) { return; }
|
||||
@@ -90,12 +145,70 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSubVoteText(GUIListBox subListBox, SubmarineInfo userData, int votes, CharacterTeamType type)
|
||||
{
|
||||
GUIComponent subElement = subListBox.Content.GetChildByUserData(userData);
|
||||
|
||||
if (subElement is null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to find the submarine element in the listbox");
|
||||
return;
|
||||
}
|
||||
var (coalIcon, sepIcon) = GetPvPIcons(subElement);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CharacterTeamType.None:
|
||||
{
|
||||
SetVoteText(subListBox, userData, votes);
|
||||
break;
|
||||
}
|
||||
case CharacterTeamType.Team1:
|
||||
{
|
||||
coalIcon.Enabled = votes > 0;
|
||||
CreateSubmarineVoteText(coalIcon, votes);
|
||||
break;
|
||||
}
|
||||
case CharacterTeamType.Team2:
|
||||
{
|
||||
sepIcon.Enabled = votes > 0;
|
||||
CreateSubmarineVoteText(sepIcon, votes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
static void CreateSubmarineVoteText(GUIComponent parent, int votes)
|
||||
{
|
||||
if (parent is null) { return; }
|
||||
var voteText = new GUITextBlock(new RectTransform(Vector2.One, parent.RectTransform, Anchor.TopLeft), $"{votes}", textAlignment: Alignment.Center)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
UserData = "votes",
|
||||
Shadow = true
|
||||
};
|
||||
voteText.RectTransform.RelativeOffset = new Vector2(0.33f, 0.33f);
|
||||
}
|
||||
|
||||
static (GUIComponent CoalitionIcon, GUIComponent SeparatistsIcon) GetPvPIcons(GUIComponent child)
|
||||
{
|
||||
var container = child.GetChild<GUILayoutGroup>();
|
||||
var imageFrame = container.GetChild<GUIFrame>();
|
||||
var coalIcon = imageFrame.GetChildByUserData(NetLobbyScreen.CoalitionIconUserData);
|
||||
var sepIcon = imageFrame.GetChildByUserData(NetLobbyScreen.SeparatistsIconUserData);
|
||||
|
||||
return (CoalitionIcon: coalIcon, SeparatistsIcon: sepIcon);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetVoteText(GUIListBox listBox, object userData, int votes)
|
||||
{
|
||||
if (userData == null) { return; }
|
||||
foreach (GUIComponent comp in listBox.Content.Children)
|
||||
{
|
||||
if (comp.UserData != userData) { continue; }
|
||||
|
||||
if (comp.FindChild("votes") is not GUITextBlock voteText)
|
||||
{
|
||||
voteText = new GUITextBlock(new RectTransform(new Point(GUI.IntScale(30), comp.Rect.Height), comp.RectTransform, Anchor.CenterRight),
|
||||
@@ -197,28 +310,48 @@ namespace Barotrauma
|
||||
msg.WritePadBits();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
GameMain.Client.ServerSettings.AllowSubVoting = inc.ReadBoolean();
|
||||
if (GameMain.Client.ServerSettings.AllowSubVoting)
|
||||
{
|
||||
UpdateVoteTexts(null, VoteType.Sub);
|
||||
bool isMultiSub = inc.ReadBoolean();
|
||||
int votableCount = inc.ReadByte();
|
||||
|
||||
List<SubmarineInfo> serversubs = new List<SubmarineInfo>();
|
||||
if (GameMain.NetLobbyScreen?.SubList?.Content != null)
|
||||
{
|
||||
foreach (GUIComponent item in GameMain.NetLobbyScreen.SubList.Content.Children)
|
||||
{
|
||||
if (item.UserData is SubmarineInfo info)
|
||||
{
|
||||
serversubs.Add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < votableCount; i++)
|
||||
{
|
||||
int votes = inc.ReadByte();
|
||||
string subName = inc.ReadString();
|
||||
List<SubmarineInfo> serversubs = new List<SubmarineInfo>();
|
||||
if (GameMain.NetLobbyScreen?.SubList?.Content != null)
|
||||
{
|
||||
foreach (GUIComponent item in GameMain.NetLobbyScreen.SubList.Content.Children)
|
||||
{
|
||||
if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); }
|
||||
}
|
||||
}
|
||||
|
||||
SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName);
|
||||
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
|
||||
SetSubVoteText(GameMain.NetLobbyScreen.SubList, sub, votes, isMultiSub ? CharacterTeamType.Team1 : CharacterTeamType.None);
|
||||
}
|
||||
|
||||
if (isMultiSub)
|
||||
{
|
||||
int separatistsCount = inc.ReadByte();
|
||||
for (int i = 0; i < separatistsCount; i++)
|
||||
{
|
||||
int votes = inc.ReadByte();
|
||||
string subName = inc.ReadString();
|
||||
|
||||
SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName);
|
||||
SetSubVoteText(GameMain.NetLobbyScreen.SubList, sub, votes, CharacterTeamType.Team2);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameMain.Client.ServerSettings.AllowModeVoting = inc.ReadBoolean();
|
||||
|
||||
Reference in New Issue
Block a user