(5a377a8ee) Unstable v0.9.1000.0

This commit is contained in:
Juan Pablo Arce
2020-05-13 12:55:42 -03:00
parent b143329701
commit a1ca41aa5d
426 changed files with 14384 additions and 5708 deletions
@@ -17,10 +17,12 @@ namespace Barotrauma.Networking
{
UInt16 ID = msg.ReadUInt16();
ChatMessageType type = (ChatMessageType)msg.ReadByte();
PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
string txt = "";
if (type != ChatMessageType.Order)
{
changeType = (PlayerConnectionChangeType)msg.ReadByte();
txt = msg.ReadString();
}
@@ -114,7 +116,7 @@ namespace Barotrauma.Networking
GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
break;
default:
GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter);
GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter, changeType);
break;
}
LastID = ID;
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Barotrauma.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
@@ -18,8 +18,8 @@ namespace Barotrauma.Networking
public static void Start(ProcessStartInfo processInfo)
{
writePipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
readPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
writePipe = new AnonymousPipeServerStream(PipeDirection.Out, System.IO.HandleInheritability.Inheritable);
readPipe = new AnonymousPipeServerStream(PipeDirection.In, System.IO.HandleInheritability.Inheritable);
writeStream = writePipe; readStream = readPipe;
@@ -38,6 +38,13 @@ namespace Barotrauma.Networking
localHandlesDisposed = true;
}
public static void ClosePipes()
{
writePipe?.Close();
readPipe?.Close();
shutDown = true;
}
public static void ShutDown()
{
Process?.Kill(); Process = null;
@@ -14,8 +14,10 @@ namespace Barotrauma.Networking
public UInt64 SteamID;
public byte ID;
public UInt16 CharacterID;
public float Karma;
public bool Muted;
public bool InGame;
public bool HasPermissions;
public bool AllowKicking;
}
@@ -44,6 +46,8 @@ namespace Barotrauma.Networking
public bool AllowKicking;
public float Karma;
public void UpdateSoundPosition()
{
if (VoipSound == null) { return; }
@@ -1,7 +1,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Threading;
using System.Xml;
@@ -100,7 +100,7 @@ namespace Barotrauma.Networking
WriteStream = null;
}
WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None);
WriteStream = File.Open(FilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
TimeStarted = Environment.TickCount;
}
@@ -259,7 +259,7 @@ namespace Barotrauma.Networking
{
newTransfer.OpenStream();
}
catch (IOException e)
catch (System.IO.IOException e)
{
if (i < maxRetries)
{
@@ -422,7 +422,7 @@ namespace Barotrauma.Networking
}
if (string.IsNullOrEmpty(fileName) ||
fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1)
fileName.IndexOfAny(Path.GetInvalidFileNameChars().ToArray()) > -1)
{
errorMessage = "Illegal characters in file name ''" + fileName + "''";
return false;
@@ -455,7 +455,7 @@ namespace Barotrauma.Networking
switch (fileTransfer.FileType)
{
case FileTransferType.Submarine:
Stream stream;
System.IO.Stream stream;
try
{
stream = SaveUtil.DecompressFiletoStream(fileTransfer.FilePath);
@@ -3,7 +3,7 @@ using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
@@ -28,6 +28,8 @@ namespace Barotrauma.Networking
get { return name; }
}
public string PendingName = string.Empty;
public void SetName(string value)
{
value = value.Replace(":", "").Replace(";", "");
@@ -50,7 +52,7 @@ namespace Barotrauma.Networking
public GUITickBox EndVoteTickBox;
private GUIComponent buttonContainer;
private NetStats netStats;
public readonly NetStats NetStats;
protected GUITickBox cameraFollowsSub;
@@ -112,6 +114,7 @@ namespace Barotrauma.Networking
public bool SpawnAsTraitor;
public string TraitorFirstObjective;
public TraitorMissionPrefab TraitorMission = null;
public byte ID
{
@@ -166,9 +169,9 @@ namespace Barotrauma.Networking
allowReconnect = true;
netStats = new NetStats();
NetStats = new NetStats();
inGameHUD = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
inGameHUD = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas), style: null)
{
CanBeFocused = false
};
@@ -482,12 +485,13 @@ namespace Barotrauma.Networking
if (requiresPw && !canStart && !connectCancelled)
{
GUI.ClearCursorWait();
reconnectBox?.Close(); reconnectBox = null;
string pwMsg = TextManager.Get("PasswordRequired");
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, 170));
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, (int)(170 * Math.Max(1.0f, GUI.Scale))));
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
{
@@ -513,6 +517,7 @@ namespace Barotrauma.Networking
{
requiresPw = false;
connectCancelled = true;
GameMain.ServerListScreen.Select();
return true;
};
@@ -564,14 +569,7 @@ namespace Barotrauma.Networking
}
}
/*TODO: reimplement
if (ShowNetStats && client?.ServerConnection != null)
{
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
netStats.AddValue(NetStats.NetStatType.SentBytes, client.ServerConnection.Statistics.SentBytes);
netStats.AddValue(NetStats.NetStatType.ResentMessages, client.ServerConnection.Statistics.ResentMessages);
netStats.Update(deltaTime);
}*/
NetStats.Update(deltaTime);
UpdateHUD(deltaTime);
@@ -669,6 +667,7 @@ namespace Barotrauma.Networking
if (header != ServerPacketHeader.STARTGAMEFINALIZE &&
header != ServerPacketHeader.ENDGAME &&
header != ServerPacketHeader.PING_REQUEST &&
roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
{
//rewind the header byte we just read
@@ -679,6 +678,31 @@ namespace Barotrauma.Networking
switch (header)
{
case ServerPacketHeader.PING_REQUEST:
IWriteMessage response = new WriteOnlyMessage();
response.Write((byte)ClientPacketHeader.PING_RESPONSE);
byte requestLen = inc.ReadByte();
response.Write(requestLen);
for (int i=0;i<requestLen;i++)
{
byte b = inc.ReadByte();
response.Write(b);
}
clientPeer.Send(response, DeliveryMethod.Unreliable);
break;
case ServerPacketHeader.CLIENT_PINGS:
byte clientCount = inc.ReadByte();
for (int i=0;i<clientCount;i++)
{
byte clientId = inc.ReadByte();
UInt16 clientPing = inc.ReadUInt16();
Client client = ConnectedClients.Find(c => c.ID == clientId);
if (client != null)
{
client.Ping = clientPing;
}
}
break;
case ServerPacketHeader.UPDATE_LOBBY:
ReadLobbyUpdate(inc);
break;
@@ -750,7 +774,7 @@ namespace Barotrauma.Networking
if (readyToStart && !CoroutineManager.IsCoroutineRunning("WaitForStartRound"))
{
CoroutineManager.StartCoroutine(GameMain.NetLobbyScreen.WaitForStartRound(startButton: null, allowCancel: false), "WaitForStartRound");
CoroutineManager.StartCoroutine(GameMain.NetLobbyScreen.WaitForStartRound(startButton: null), "WaitForStartRound");
}
break;
case ServerPacketHeader.STARTGAME:
@@ -1056,11 +1080,13 @@ namespace Barotrauma.Networking
var missionPrefab = TraitorMissionPrefab.List.Find(t => t.Identifier == missionIdentifier);
Sprite icon = missionPrefab?.Icon;
switch(messageType) {
switch(messageType)
{
case TraitorMessageType.Objective:
var isTraitor = !string.IsNullOrEmpty(message);
SpawnAsTraitor = isTraitor;
TraitorFirstObjective = message;
TraitorMission = missionPrefab;
if (Character != null)
{
Character.IsTraitor = isTraitor;
@@ -1422,6 +1448,15 @@ namespace Barotrauma.Networking
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
Submarine.MainSubs[i].TeamID = teamID;
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null) { continue; }
if (item.Submarine != Submarine.MainSubs[i] && !Submarine.MainSubs[i].DockedTo.Contains(item.Submarine)) { continue; }
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
{
wifiComponent.TeamID = Submarine.MainSubs[i].TeamID;
}
}
foreach (Submarine sub in Submarine.MainSubs[i].DockedTo)
{
sub.TeamID = teamID;
@@ -1503,7 +1538,7 @@ namespace Barotrauma.Networking
var matchingSub =
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash);
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash, tryLoad: false);
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
serverSubmarines.Add(matchingSub);
@@ -1537,9 +1572,11 @@ namespace Barotrauma.Networking
string name = inc.ReadString();
string preferredJob = inc.ReadString();
UInt16 characterID = inc.ReadUInt16();
float karma = inc.ReadSingle();
bool muted = inc.ReadBoolean();
bool inGame = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean();
bool hasPermissions = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean() || IsServerOwner;
inc.ReadPadBits();
tempClients.Add(new TempClient
@@ -1550,8 +1587,10 @@ namespace Barotrauma.Networking
Name = name,
PreferredJob = preferredJob,
CharacterID = characterID,
Karma = karma,
Muted = muted,
InGame = inGame,
HasPermissions = hasPermissions,
AllowKicking = allowKicking
});
}
@@ -1579,7 +1618,9 @@ namespace Barotrauma.Networking
existingClient.NameID = tc.NameID;
existingClient.PreferredJob = tc.PreferredJob;
existingClient.Character = null;
existingClient.Karma = tc.Karma;
existingClient.Muted = tc.Muted;
existingClient.HasPermissions = tc.HasPermissions;
existingClient.InGame = tc.InGame;
existingClient.AllowKicking = tc.AllowKicking;
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
@@ -1852,8 +1893,8 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError("Writing object data to \"crashreport_object.bin\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
using (FileStream fl = File.Open("crashreport_object.bin", FileMode.Create))
using (BinaryWriter sw = new BinaryWriter(fl))
using (FileStream fl = File.Open("crashreport_object.bin", System.IO.FileMode.Create))
using (System.IO.BinaryWriter sw = new System.IO.BinaryWriter(fl))
{
sw.Write(inc.Buffer, (int)(prevBytePos - prevByteLength), (int)(prevByteLength));
}
@@ -2085,7 +2126,8 @@ namespace Barotrauma.Networking
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
}
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
GameMain.GameSession?.SubmarineInfo?.Reload();
GameMain.GameSession?.SubmarineInfo?.CheckSubsLeftBehind();
if (GameMain.GameSession?.SubmarineInfo?.Name != null)
{
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.SubmarineInfo);
@@ -2540,6 +2582,11 @@ namespace Barotrauma.Networking
inGameHUD.AddToGUIUpdateList();
GameMain.NetLobbyScreen.FileTransferFrame?.AddToGUIUpdateList();
}
serverSettings.AddToGUIUpdateList();
if (serverSettings.ServerLog.LogFrame != null) serverSettings.ServerLog.LogFrame.AddToGUIUpdateList();
GameMain.NetLobbyScreen?.PlayerFrame?.AddToGUIUpdateList();
}
public void UpdateHUD(float deltaTime)
@@ -2583,7 +2630,7 @@ namespace Barotrauma.Networking
if (GUI.KeyboardDispatcher.Subscriber == null)
{
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 0);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100);
if (chatKeyHit || radioKeyHit)
{
@@ -2629,8 +2676,6 @@ namespace Barotrauma.Networking
}
}
}
serverSettings.AddToGUIUpdateList();
if (serverSettings.ServerLog.LogFrame != null) serverSettings.ServerLog.LogFrame.AddToGUIUpdateList();
}
public virtual void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
@@ -2716,15 +2761,15 @@ namespace Barotrauma.Networking
if (!ShowNetStats) return;
netStats.Draw(spriteBatch, new Rectangle(300, 10, 300, 150));
NetStats.Draw(spriteBatch, new Rectangle(300, 10, 300, 150));
/* TODO: reimplement
int width = 200, height = 300;
int x = GameMain.GraphicsWidth - width, y = (int)(GameMain.GraphicsHeight * 0.3f);
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black * 0.7f, true);
GUI.Font.DrawString(spriteBatch, "Network statistics:", new Vector2(x + 10, y + 10), Color.White);
/* TODO: reimplement
if (client.ServerConnection != null)
{
GUI.Font.DrawString(spriteBatch, "Ping: " + (int)(client.ServerConnection.AverageRoundtripTime * 1000.0f) + " ms", new Vector2(x + 10, y + 25), Color.White);
@@ -2743,73 +2788,106 @@ namespace Barotrauma.Networking
}*/
}
public virtual bool SelectCrewCharacter(Character character, GUIComponent characterFrame)
public virtual bool SelectCrewCharacter(Character character, GUIComponent frame)
{
if (character == null) { return false; }
if (character == null) return false;
if (character != myCharacter)
{
var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.Character == character);
if (client == null) { return false; }
if (client == null) return false;
var content = new GUIFrame(new RectTransform(new Vector2(0.9f, 1.0f - characterFrame.RectTransform.RelativeSize.Y), characterFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter),
style: null);
var mute = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.TopCenter),
TextManager.Get("Mute"))
{
Selected = client.MutedLocally,
OnSelected = (tickBox) => { client.MutedLocally = tickBox.Selected; return true; }
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.BottomCenter), isHorizontal: true)
{
RelativeSpacing = 0.05f,
ChildAnchor = Anchor.CenterLeft,
Stretch = true
};
if (HasPermission(ClientPermissions.Ban))
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Ban"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.BanPlayer(client); return false; }
};
}
if (HasPermission(ClientPermissions.Kick))
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Kick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.KickPlayer(client); return false; }
};
}
else if (serverSettings.Voting.AllowVoteKick)
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("VoteToKick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { VoteForKick(client); btn.Enabled = false; return true; }
};
if (GameMain.NetworkMember.ConnectedClients != null)
{
kickVoteButton.Enabled = !client.HasKickVoteFromID(myID);
}
}
CreateSelectionRelatedButtons(client, frame);
}
return true;
}
public virtual bool SelectCrewClient(Client client, GUIComponent frame)
{
if (client == null || client.ID == ID) return false;
CreateSelectionRelatedButtons(client, frame);
return true;
}
private void CreateSelectionRelatedButtons(Client client, GUIComponent frame)
{
var content = new GUIFrame(new RectTransform(new Vector2(1f, 1.0f - frame.RectTransform.RelativeSize.Y), frame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter),
style: null);
var mute = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, Anchor.TopCenter),
TextManager.Get("Mute"))
{
Selected = client.MutedLocally,
OnSelected = (tickBox) => { client.MutedLocally = tickBox.Selected; return true; }
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.35f), content.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft)
{
RelativeSpacing = 0.05f,
Stretch = true
};
if (!GameMain.Client.GameStarted || (GameMain.Client.Character == null || GameMain.Client.Character.IsDead) && (client.Character == null || client.Character.IsDead))
{
var messageButton = new GUIButton(new RectTransform(new Vector2(1f, 0.2f), content.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0f, buttonContainer.RectTransform.RelativeSize.Y) },
TextManager.Get("message"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) =>
{
chatBox.InputBox.Text = $"{client.Name}; ";
CoroutineManager.StartCoroutine(selectCoroutine());
return false;
}
};
}
// Need a delayed selection due to the inputbox being deselected when a left click occurs outside of it
IEnumerable<object> selectCoroutine()
{
yield return new WaitForSeconds(0.01f, true);
chatBox.InputBox.Select(chatBox.InputBox.Text.Length);
}
if (HasPermission(ClientPermissions.Ban) && client.AllowKicking)
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Ban"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.BanPlayer(client); return false; }
};
}
if (HasPermission(ClientPermissions.Kick) && client.AllowKicking)
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("Kick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { GameMain.NetLobbyScreen.KickPlayer(client); return false; }
};
}
else if (serverSettings.Voting.AllowVoteKick && client.AllowKicking)
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.9f), buttonContainer.RectTransform),
TextManager.Get("VoteToKick"), style: "GUIButtonSmall")
{
UserData = client,
OnClicked = (btn, userdata) => { VoteForKick(client); btn.Enabled = false; return true; }
};
if (GameMain.NetworkMember.ConnectedClients != null)
{
kickVoteButton.Enabled = !client.HasKickVoteFromID(myID);
}
}
}
public void CreateKickReasonPrompt(string clientName, bool ban, bool rangeBan = false)
{
var banReasonPrompt = new GUIMessageBox(
TextManager.Get(ban ? "BanReasonPrompt" : "KickReasonPrompt"),
"", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") }, new Vector2(0.25f, 0.2f), new Point(400, 200));
"", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") }, new Vector2(0.25f, 0.22f), new Point(400, 220));
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.6f), banReasonPrompt.InnerFrame.RectTransform, Anchor.Center));
var banReasonBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.3f), content.RectTransform))
@@ -2823,14 +2901,16 @@ namespace Barotrauma.Networking
if (ban)
{
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform), TextManager.Get("BanDuration"));
permaBanTickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) },
TextManager.Get("BanPermanent"))
var labelContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), content.RectTransform), isHorizontal: false);
new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), labelContainer.RectTransform), TextManager.Get("BanDuration")) { Padding = Vector4.Zero };
var buttonContent = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), labelContainer.RectTransform), isHorizontal: true);
permaBanTickBox = new GUITickBox(new RectTransform(new Vector2(0.4f, 0.15f), buttonContent.RectTransform), TextManager.Get("BanPermanent"))
{
Selected = true
};
var durationContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.15f), content.RectTransform), isHorizontal: true)
var durationContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), buttonContent.RectTransform), isHorizontal: true)
{
Visible = false
};
@@ -2930,6 +3010,11 @@ namespace Barotrauma.Networking
if (GameMain.GameSession?.GameMode != null)
{
errorLines.Add("Game mode: " + GameMain.GameSession.GameMode.Name);
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
{
errorLines.Add("Campaign ID: " + campaign.CampaignID);
errorLines.Add("Campaign save ID: " + campaign.LastSaveID + "(pending: " + campaign.PendingSaveID + ")");
}
}
if (GameMain.GameSession?.Submarine != null)
{
@@ -2938,6 +3023,13 @@ namespace Barotrauma.Networking
if (Level.Loaded != null)
{
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + Level.Loaded.EqualityCheckVal);
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
errorLines.Add("Entities:");
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate)
{
errorLines.Add(" " + e.ID + ": " + e.ToString());
}
errorLines.Add("Entity count after generating level: " + Level.Loaded.EntityCountAfterGenerate);
}
errorLines.Add("Entity IDs:");
@@ -47,11 +47,30 @@ namespace Barotrauma
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(StructureDamageKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(DamageFriendlyKarmaDecrease));
//hide these for now if a localized text is not available
if (TextManager.ContainsTag("Karma." + nameof(StunFriendlyKarmaDecrease)))
{
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, nameof(StunFriendlyKarmaDecrease));
}
if (TextManager.ContainsTag("Karma." + nameof(StunFriendlyKarmaDecreaseThreshold)))
{
CreateLabeledSlider(parent, 0.0f, 10.0f, 1.0f, nameof(StunFriendlyKarmaDecreaseThreshold));
}
CreateLabeledSlider(parent, 0.0f, 100.0f, 1.0f, nameof(ReactorMeltdownKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, nameof(ReactorOverheatKarmaDecrease));
CreateLabeledNumberInput(parent, 0, 20, nameof(AllowedWireDisconnectionsPerMinute));
CreateLabeledSlider(parent, 0.0f, 20.0f, 0.5f, nameof(WireDisconnectionKarmaDecrease));
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, nameof(SpamFilterKarmaDecrease));
//hide these for now if a localized text is not available
if (TextManager.ContainsTag("Karma." + nameof(DangerousItemStealKarmaDecrease)))
{
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, nameof(DangerousItemStealKarmaDecrease));
}
if (TextManager.ContainsTag("Karma." + nameof(DangerousItemStealBots)))
{
CreateLabeledTickBox(parent, nameof(DangerousItemStealBots));
}
}
private void CreateLabeledSlider(GUIComponent parent, float min, float max, float step, string propertyName)
@@ -14,10 +14,10 @@ namespace Barotrauma.Networking
ResentMessages = 2
}
private Graph[] graphs;
private readonly Graph[] graphs;
private float[] totalValue;
private float[] lastValue;
private readonly float[] totalValue;
private readonly float[] lastValue;
const float UpdateInterval = 0.1f;
float updateTimer;
@@ -37,9 +37,7 @@ namespace Barotrauma.Networking
public void AddValue(NetStatType statType, float value)
{
float valueChange = value - lastValue[(int)statType];
totalValue[(int)statType] += valueChange;
lastValue[(int)statType] = value;
}
@@ -51,7 +49,6 @@ namespace Barotrauma.Networking
for (int i = 0; i < 3; i++)
{
graphs[i].Update(totalValue[i] / UpdateInterval);
totalValue[i] = 0.0f;
}
@@ -64,23 +61,22 @@ namespace Barotrauma.Networking
GUI.DrawRectangle(spriteBatch, rect, Color.Black * 0.4f, true);
graphs[(int)NetStatType.ReceivedBytes].Draw(spriteBatch, rect, null, 0.0f, Color.Cyan);
graphs[(int)NetStatType.SentBytes].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Orange);
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Red);
if (graphs[(int)NetStatType.ResentMessages].Average() > 0)
{
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Red);
GUI.SmallFont.DrawString(spriteBatch, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.Right + 10, rect.Y + 50), GUI.Style.Red);
}
GUI.SmallFont.DrawString(spriteBatch,
"Peak received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].LargestValue()) + "/s " +
"Avg received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].Average()) + "/s",
new Vector2(rect.Right + 10, rect.Y + 10), Color.Cyan);
GUI.SmallFont.DrawString(spriteBatch, "Peak sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].LargestValue()) + "/s " +
"Avg sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].Average()) + "/s",
new Vector2(rect.Right + 10, rect.Y + 30), GUI.Style.Orange);
GUI.SmallFont.DrawString(spriteBatch, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.Right + 10, rect.Y + 50), GUI.Style.Red);
#if DEBUG
/*int y = 10;
@@ -39,7 +39,10 @@ namespace Barotrauma.Networking
contentPackageOrderReceived = false;
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
{
UseDualModeSockets = GameMain.Config.UseDualModeSockets
};
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
@@ -94,6 +97,9 @@ namespace Barotrauma.Networking
incomingLidgrenMessages.Clear();
netClient.ReadMessages(incomingLidgrenMessages);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, netClient.Statistics.ReceivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, netClient.Statistics.SentBytes);
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
{
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }
@@ -18,6 +18,8 @@ namespace Barotrauma.Networking
private double timeout;
private double heartbeatTimer;
private long sentBytes, receivedBytes;
private List<IReadMessage> incomingInitializationMessages;
private List<IReadMessage> incomingDataMessages;
@@ -63,6 +65,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)ConnectionInitialization.ConnectionStarted);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
@@ -99,11 +102,11 @@ namespace Barotrauma.Networking
if (isConnectionInitializationStep)
{
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8+32);
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8 + 32);
ulong lobbyId = low + (high << 32);
Steam.SteamManager.JoinLobby(lobbyId, false);
IReadMessage inc = new ReadOnlyMessage(data, false, 1+8, dataLength - 9, ServerConnection);
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - 9, ServerConnection);
if (initializationStep != ConnectionInitialization.Success)
{
incomingInitializationMessages.Add(inc);
@@ -137,15 +140,20 @@ namespace Barotrauma.Networking
timeout -= deltaTime;
heartbeatTimer -= deltaTime;
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
for (int i = 0; i < 100; i++)
{
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
receivedBytes += packet?.Data.Length ?? 0;
}
}
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, receivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, sentBytes);
if (heartbeatTimer < 0.0)
{
IWriteMessage outMsg = new WriteOnlyMessage();
@@ -153,6 +161,7 @@ namespace Barotrauma.Networking
outMsg.Write((byte)PacketHeader.IsHeartbeatMessage);
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Unreliable);
sentBytes += outMsg.LengthBytes;
heartbeatTimer = 5.0;
}
@@ -226,6 +235,7 @@ namespace Barotrauma.Networking
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.ContentPackageOrder:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
@@ -253,7 +263,7 @@ namespace Barotrauma.Networking
}
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
@@ -333,6 +343,7 @@ namespace Barotrauma.Networking
private void Send(byte[] buf, int length, Steamworks.P2PSend sendType)
{
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
sentBytes += length + 4;
if (!successSend)
{
if (sendType != Steamworks.P2PSend.Reliable)
@@ -340,6 +351,7 @@ namespace Barotrauma.Networking
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, buf, length + 4, 0, sendType);
sentBytes += length + 4;
}
if (!successSend)
{
@@ -363,6 +375,7 @@ namespace Barotrauma.Networking
heartbeatTimer = 5.0;
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
public override void Close(string msg = null)
@@ -379,6 +392,7 @@ namespace Barotrauma.Networking
outMsg.Write(msg ?? "Disconnected");
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
Thread.Sleep(100);
@@ -13,7 +13,9 @@ namespace Barotrauma.Networking
private bool isActive;
private ConnectionInitialization initializationStep;
private UInt64 selfSteamID;
private readonly UInt64 selfSteamID;
private long sentBytes, receivedBytes;
class RemotePeer
{
@@ -204,22 +206,24 @@ namespace Barotrauma.Networking
}
}
for (int i=0;i<100;i++)
for (int i = 0; i < 100; i++)
{
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
receivedBytes += packet?.Data.Length ?? 0;
}
}
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.ReceivedBytes, receivedBytes);
GameMain.Client?.NetStats?.AddValue(NetStats.NetStatType.SentBytes, sentBytes);
while (ChildServerRelay.Read(out byte[] incBuf))
{
ChildServerRelay.DisposeLocalHandles();
IReadMessage inc = new ReadOnlyMessage(incBuf, false, 0, incBuf.Length, ServerConnection);
HandleDataMessage(inc);
}
}
@@ -295,6 +299,7 @@ namespace Barotrauma.Networking
}
bool successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
if (!successSend)
{
@@ -303,6 +308,7 @@ namespace Barotrauma.Networking
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
sendType = Steamworks.P2PSend.Reliable;
successSend = Steamworks.SteamNetworking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, 0, sendType);
sentBytes += p2pData.Length;
}
if (!successSend)
{
@@ -336,7 +342,6 @@ namespace Barotrauma.Networking
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
Array.Resize(ref msgToSend, outMsg.LengthBytes);
ChildServerRelay.Write(msgToSend);
return;
}
else
@@ -369,6 +374,7 @@ namespace Barotrauma.Networking
outMsg.Write(msg);
Steamworks.SteamNetworking.SendP2PPacket(peer.SteamID, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
sentBytes += outMsg.LengthBytes;
}
else
{
@@ -405,7 +411,7 @@ namespace Barotrauma.Networking
ClosePeerSession(remotePeers[i]);
}
ChildServerRelay.ShutDown();
ChildServerRelay.ClosePipes();
OnDisconnect?.Invoke();
@@ -2,6 +2,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Extensions;
namespace Barotrauma.Networking
{
@@ -9,15 +11,28 @@ namespace Barotrauma.Networking
{
public GUIButton LogFrame;
private GUIListBox listBox;
private GUIButton reverseButton;
private string msgFilter;
private bool reverseOrder = false;
private bool OnReverseClicked(GUIButton btn, object obj)
{
SetMessageReversal(!reverseOrder);
return false;
}
public void CreateLogFrame()
{
LogFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker")
LogFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null)
{
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) LogFrame = null; return true; }
};
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, LogFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
new GUIButton(new RectTransform(Vector2.One, LogFrame.RectTransform), "", style: null).OnClicked += (btn, userData) =>
{
LogFrame = null;
@@ -80,7 +95,17 @@ namespace Barotrauma.Networking
GUI.KeyboardDispatcher.Subscriber = searchBox;
filterArea.RectTransform.MinSize = new Point(0, filterArea.RectTransform.Children.Max(c => c.MinSize.Y));
listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), rightColumn.RectTransform));
GUILayoutGroup listBoxLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.95f), rightColumn.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.0f
};
reverseButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), listBoxLayout.RectTransform), style: "UIToggleButtonVertical");
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
reverseButton.OnClicked = OnReverseClicked;
listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), listBoxLayout.RectTransform));
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.05f), rightColumn.RectTransform), TextManager.Get("Close"))
{
@@ -107,7 +132,7 @@ namespace Barotrauma.Networking
msgFilter = "";
}
public void AssignLogFrame(GUIListBox inListBox, GUIComponent tickBoxContainer, GUITextBox searchBox)
public void AssignLogFrame(GUIButton inReverseButton, GUIListBox inListBox, GUIComponent tickBoxContainer, GUITextBox searchBox)
{
searchBox.OnTextChanged += (textBox, text) =>
{
@@ -144,6 +169,10 @@ namespace Barotrauma.Networking
inListBox.ClearChildren();
listBox = inListBox;
reverseButton = inReverseButton;
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
reverseButton.OnClicked = OnReverseClicked;
var currLines = lines.ToList();
foreach (LogMessage line in currLines)
{
@@ -158,8 +187,34 @@ namespace Barotrauma.Networking
{
float prevSize = listBox.BarSize;
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
line.Text, wrap: true, font: GUI.SmallFont)
GUIFrame textContainer = null;
Anchor anchor = Anchor.TopLeft;
Pivot pivot = Pivot.TopLeft;
if (line.RichData != null)
{
foreach (var data in line.RichData)
{
UInt64 id = 0;
if (!UInt64.TryParse(data.Metadata, out id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
if (client != null && client.Karma < 40.0f)
{
textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
style: null, color: new Color(0xff111155))
{
CanBeFocused = false
};
anchor = Anchor.CenterLeft;
pivot = Pivot.CenterLeft;
break;
}
}
}
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), (textContainer ?? listBox.Content).RectTransform, anchor, pivot),
line.RichData, line.SanitizedText, wrap: true, font: GUI.SmallFont)
{
TextColor = messageColor[line.Type],
Visible = !msgTypeHidden[(int)line.Type],
@@ -167,6 +222,38 @@ namespace Barotrauma.Networking
UserData = line
};
if (textContainer != null)
{
textContainer.RectTransform.NonScaledSize = new Point(textContainer.RectTransform.NonScaledSize.X, textBlock.RectTransform.NonScaledSize.Y + 5);
textBlock.SetTextPos();
textBlock.RectTransform.Resize(textContainer.RectTransform.NonScaledSize);
}
if (reverseOrder)
{
textBlock.RectTransform.SetAsFirstChild();
}
if (line.RichData != null)
{
foreach (var data in line.RichData)
{
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
{
Data = data,
OnClick = (component, area) =>
{
UInt64 id = 0;
if (!UInt64.TryParse(area.Data.Metadata, out id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id);
client ??= GameMain.Client.ConnectedClients.Find(c => c.ID == id);
if (client == null) { return; }
GameMain.NetLobbyScreen.SelectPlayer(client);
}
});
}
}
if ((prevSize == 1.0f && listBox.BarScroll == 0.0f) || (prevSize < 1.0f && listBox.BarScroll == 1.0f)) listBox.BarScroll = 1.0f;
}
@@ -195,6 +282,16 @@ namespace Barotrauma.Networking
return true;
}
private void SetMessageReversal(bool reverse)
{
if (reverseOrder == reverse) { return; }
reverseOrder = reverse;
reverseButton.Children.ForEach(c => c.SpriteEffects = reverseOrder ? SpriteEffects.FlipVertically : SpriteEffects.None);
listBox.Content.RectTransform.ReverseChildren();
}
public bool ClearFilter(GUIComponent button, object obj)
{
var searchBox = button.UserData as GUITextBox;
@@ -266,7 +266,9 @@ namespace Barotrauma.Networking
}
//background frame
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null, color: Color.Black * 0.5f);
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, settingsFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
new GUIButton(new RectTransform(Vector2.One, settingsFrame.RectTransform), "", style: null).OnClicked += (btn, userData) =>
{
if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) { ToggleSettingsFrame(btn, userData); }
@@ -2,14 +2,14 @@
using RestSharp;
using System;
using System.Collections.Generic;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using RestSharp.Contrib;
using System.Xml.Linq;
using System.Xml;
using Color = Microsoft.Xna.Framework.Color;
using System.Runtime.InteropServices;
namespace Barotrauma.Steam
{
@@ -37,6 +37,11 @@ namespace Barotrauma.Steam
popularTags.Insert(i, commonness.Key);
i++;
}
LogSteamworksNetworkingDelegate = LogSteamworksNetworking;
IntPtr logSteamworksNetworkingPtr = Marshal.GetFunctionPointerForDelegate(LogSteamworksNetworkingDelegate);
Steamworks.SteamNetworkingUtils.SetDebugOutputFunction(Steamworks.Data.DebugOutputType.Everything, logSteamworksNetworkingPtr);
}
}
catch (DllNotFoundException)
@@ -63,6 +68,15 @@ namespace Barotrauma.Steam
}
}
public static bool NetworkingDebugLog = false;
private static Steamworks.Data.FSteamNetworkingSocketsDebugOutput LogSteamworksNetworkingDelegate;
private static void LogSteamworksNetworking(Steamworks.Data.DebugOutputType nType, string pszMsg)
{
if (NetworkingDebugLog) { DebugConsole.NewMessage($"({nType}) {pszMsg}", Color.Orange); }
}
private static void UpdateProjectSpecific(float deltaTime)
{
if (ugcSubscriptionTasks != null)
@@ -235,7 +249,8 @@ namespace Barotrauma.Steam
}
};
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide();
//TODO: find a better strategy to fetch all lobbies, this is gonna take forever if we actually have 10000 lobbies
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide().WithMaxResults(10000);
TaskPool.Add(Task.Run(async () =>
{
@@ -355,7 +370,7 @@ namespace Barotrauma.Steam
if (Enum.TryParse(lobby.GetData("traitors"), out YesNoMaybe traitorsEnabled)) { serverInfo.TraitorsEnabled = traitorsEnabled; }
serverInfo.GameStarted = lobby.GetData("gamestarted") == "True";
serverInfo.GameMode = lobby.GetData("gamemode");
serverInfo.GameMode = lobby.GetData("gamemode") ?? "";
if (Enum.TryParse(lobby.GetData("playstyle"), out PlayStyle playStyle)) serverInfo.PlayStyle = playStyle;
if (serverInfo.ContentPackageNames.Count != serverInfo.ContentPackageHashes.Count ||
@@ -739,7 +754,7 @@ namespace Barotrauma.Steam
if (!CheckWorkshopItemEnabled(existingItem))
{
if (!EnableWorkShopItem(existingItem, false, out string errorMsg))
if (!EnableWorkShopItem(existingItem, out string errorMsg))
{
DebugConsole.NewMessage(errorMsg, Color.Red);
new GUIMessageBox(
@@ -866,6 +881,10 @@ namespace Barotrauma.Steam
DebugConsole.NewMessage("Published workshop item " + item?.Title + " successfully.", Microsoft.Xna.Framework.Color.LightGreen);
contentPackage.SteamWorkshopUrl = $"http://steamcommunity.com/sharedfiles/filedetails/?source=Facepunch.Steamworks&id={task.Result.FileId.Value}";
//NOTE: This sets InstallTime one hour into the future to guarantee
//that the published content package won't be autoupdated incorrectly.
//Change if it causes issues.
contentPackage.InstallTime = DateTime.UtcNow + TimeSpan.FromHours(1);
contentPackage.Save(contentPackage.Path);
SubscribeToWorkshopItem(task.Result.FileId);
@@ -877,7 +896,7 @@ namespace Barotrauma.Steam
/// <summary>
/// Enables a workshop item by moving it to the game folder.
/// </summary>
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
{
if (!(item?.IsInstalled ?? false))
{
@@ -901,12 +920,21 @@ namespace Barotrauma.Steam
};
string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);
if (ContentPackage.List.Any(cp => cp.Path.CleanUpPath() == newContentPackagePath.CleanUpPath()))
List<ContentPackage> existingPackages = ContentPackage.List.Where(cp => cp.Path.CleanUpPath() == newContentPackagePath.CleanUpPath()).ToList();
if (existingPackages.Any())
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorSamePathInstalled",
new string[] { "[itemname]", "[itempath]" },
new string[] { item?.Title, Path.GetDirectoryName(newContentPackagePath) });
return false;
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorSamePathInstalled",
new string[] { "[itemname]", "[itempath]" },
new string[] { item?.Title, Path.GetDirectoryName(newContentPackagePath) });
return false;
}
else
{
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl,
false);
}
}
if (!contentPackage.IsCompatible())
@@ -929,15 +957,9 @@ namespace Barotrauma.Steam
{
if (modCopiesInProgress.ContainsKey(item.Value.Id))
{
if (!modCopiesInProgress[item.Value.Id].IsCompleted &&
!modCopiesInProgress[item.Value.Id].IsFaulted &&
!modCopiesInProgress[item.Value.Id].IsCanceled)
{
errorMsg = ""; return true;
}
modCopiesInProgress.Remove(item.Value.Id);
errorMsg = ""; return true;
}
newTask = CopyWorkShopItemAsync(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite);
newTask = CopyWorkShopItemAsync(item, contentPackage, newContentPackagePath, metaDataFilePath);
modCopiesInProgress.Add(item.Value.Id, newTask);
}
@@ -945,67 +967,85 @@ namespace Barotrauma.Steam
contentPackage,
(task, cp) =>
{
if (task.IsFaulted || task.IsCanceled)
try
{
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\"", task.Exception);
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
if (!string.IsNullOrWhiteSpace(task.Result))
{
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\": {task.Result}");
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
GameMain.Config.SuppressModFolderWatcher = true;
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
{
SteamWorkshopUrl = item?.Url,
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
};
foreach (ContentFile contentFile in newPackage.Files)
{
contentFile.Path = CorrectContentFilePath(contentFile.Path, cp, true);
}
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
}
newPackage.Save(newContentPackagePath);
ContentPackage.List.Add(newPackage);
if (selectContentPackage)
{
if (newPackage.CorePackage)
if (task.IsFaulted || task.IsCanceled)
{
GameMain.Config.SelectCorePackage(newPackage);
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\"", task.Exception);
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
else
if (!string.IsNullOrWhiteSpace(task.Result))
{
GameMain.Config.SelectContentPackage(newPackage);
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\": {task.Result}");
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
GameMain.Config.SaveNewPlayerConfig();
GameMain.Config.WarnIfContentPackageSelectionDirty();
GameMain.Config.SuppressModFolderWatcher = true;
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
{
SubmarineInfo.RefreshSavedSubs();
SteamWorkshopUrl = item?.Url,
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
};
foreach (ContentFile contentFile in newPackage.Files)
{
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentFile.Type, cp, true);
}
foreach (ContentFile file in existingPackages.SelectMany(p => p.Files))
{
string path = CorrectContentFilePath(file.Path, file.Type, cp, true).CleanUpPath();
if (newPackage.Files.Any(f => f.Path.CleanUpPath() == path)) { continue; }
newPackage.AddFile(path, file.Type);
}
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
}
newPackage.Save(newContentPackagePath);
ContentPackage.List.Add(newPackage);
if (selectContentPackage)
{
if (newPackage.CorePackage)
{
GameMain.Config.SelectCorePackage(newPackage);
}
else
{
GameMain.Config.SelectContentPackage(newPackage);
}
GameMain.Config.SaveNewPlayerConfig();
GameMain.Config.WarnIfContentPackageSelectionDirty();
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
{
SubmarineInfo.RefreshSavedSubs();
}
}
else if (!suppressInstallNotif)
{
GameMain.MainMenuScreen?.SetEnableModsNotification(true);
}
GameMain.Config.SuppressModFolderWatcher = false;
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Green);
}
else if (!suppressInstallNotif)
catch
{
GameMain.MainMenuScreen?.SetEnableModsNotification(true);
throw;
}
finally
{
modCopiesInProgress.Remove(item.Value.Id);
}
GameMain.Config.SuppressModFolderWatcher = false;
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Green);
});
errorMsg = "";
@@ -1016,7 +1056,7 @@ namespace Barotrauma.Steam
/// Asynchronously copies a Workshop item into the Mods folder.
/// </summary>
/// <returns>Returns an empty string on success, otherwise returns an error message.</returns>
private async static Task<string> CopyWorkShopItemAsync(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite)
private async static Task<string> CopyWorkShopItemAsync(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath)
{
await Task.Yield();
@@ -1029,13 +1069,13 @@ namespace Barotrauma.Steam
Directory.CreateDirectory(targetPath);
File.WriteAllText(copyingPath, "TEMPORARY FILE");
SaveUtil.CopyFolder(item?.Directory, targetPath, copySubDirs: true, overwriteExisting: true);
SaveUtil.CopyFolder(item?.Directory, targetPath, copySubDirs: true, overwriteExisting: false);
File.Delete(copyingPath);
return "";
}
var allPackageFiles = Directory.GetFiles(item?.Directory, "*", SearchOption.AllDirectories);
var allPackageFiles = Directory.GetFiles(item?.Directory, "*", System.IO.SearchOption.AllDirectories);
List<string> nonContentFiles = new List<string>();
foreach (string file in allPackageFiles)
{
@@ -1046,27 +1086,24 @@ namespace Barotrauma.Steam
nonContentFiles.Add(relativePath);
}
if (!allowFileOverwrite)
/*if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath))
{
if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath))
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, newContentPackagePath });
DebugConsole.NewMessage(errorMsg, Color.Red);
return errorMsg;
}
foreach (ContentFile contentFile in contentPackage.Files)
{
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
if (File.Exists(sourceFile) && File.Exists(contentFile.Path) && !CheckFileEquality(sourceFile, contentFile.Path))
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, newContentPackagePath });
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, contentFile.Path });
DebugConsole.NewMessage(errorMsg, Color.Red);
return errorMsg;
}
foreach (ContentFile contentFile in contentPackage.Files)
{
string sourceFile = Path.Combine(item?.Directory, contentFile.Path);
if (File.Exists(sourceFile) && File.Exists(contentFile.Path) && !CheckFileEquality(sourceFile, contentFile.Path))
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, contentFile.Path });
DebugConsole.NewMessage(errorMsg, Color.Red);
return errorMsg;
}
}
}
}*/
Directory.CreateDirectory(targetPath);
File.WriteAllText(copyingPath, "TEMPORARY FILE");
@@ -1084,7 +1121,7 @@ namespace Barotrauma.Steam
}
}
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage,
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentFile.Type, contentPackage,
contentFile.Type != ContentType.Submarine);
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
@@ -1122,16 +1159,16 @@ namespace Barotrauma.Steam
//make sure the destination directory exists
Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path));
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: true);
CorrectContentFileCopy(contentPackage, sourceFile, contentFile.Path, overwrite: false);
}
foreach (string nonContentFile in nonContentFiles)
{
string sourceFile = Path.Combine(item?.Directory, nonContentFile);
if (!File.Exists(sourceFile)) { continue; }
string destinationPath = CorrectContentFilePath(nonContentFile, contentPackage, false);
string destinationPath = CorrectContentFilePath(nonContentFile, ContentType.None, contentPackage, false);
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: false);
}
File.Delete(copyingPath);
@@ -1154,7 +1191,7 @@ namespace Barotrauma.Steam
}
}
private static void RemoveMods(Func<ContentPackage, bool> predicate)
private static void RemoveMods(Func<ContentPackage, bool> predicate, bool delete = true)
{
var toRemove = ContentPackage.List.Where(predicate).ToList();
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
@@ -1170,16 +1207,19 @@ namespace Barotrauma.Steam
}
}
foreach (var cp in toRemove)
if (delete)
{
try
foreach (var cp in toRemove)
{
string path = Path.GetDirectoryName(cp.Path);
if (Directory.Exists(path)) { Directory.Delete(path, true); }
}
catch (Exception e)
{
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
try
{
string path = Path.GetDirectoryName(cp.Path);
if (Directory.Exists(path)) { Directory.Delete(path, true); }
}
catch (Exception e)
{
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
}
}
}
@@ -1245,7 +1285,7 @@ namespace Barotrauma.Steam
string metaDataPath = Path.Combine(item?.Directory, MetadataFileName);
if (!File.Exists(metaDataPath))
{
throw new FileNotFoundException("Metadata file for the Workshop item \"" + item?.Title + "\" not found. The file may be corrupted.");
throw new System.IO.FileNotFoundException("Metadata file for the Workshop item \"" + item?.Title + "\" not found. The file may be corrupted.");
}
ContentPackage contentPackage = new ContentPackage(metaDataPath);
@@ -1268,7 +1308,7 @@ namespace Barotrauma.Steam
{
metaDataPath = Path.Combine(item?.Directory, MetadataFileName);
}
catch (ArgumentException e)
catch (ArgumentException)
{
string errorMessage = "Metadata file for the Workshop item \"" + item?.Title +
"\" not found. Could not combine path (" + (item?.Directory ?? "directory name empty") + ").";
@@ -1328,6 +1368,8 @@ namespace Barotrauma.Steam
public static async Task<bool> AutoUpdateWorkshopItemsAsync()
{
await Task.Yield();
if (!isInitialized) { return false; }
var query = new Steamworks.Ugc.Query(Steamworks.UgcType.All)
@@ -1343,6 +1385,8 @@ namespace Barotrauma.Steam
GameMain.Config.SuppressModFolderWatcher = false;
List<string> updateNotifications = new List<string>();
foreach (var item in items)
{
try
@@ -1353,7 +1397,7 @@ namespace Barotrauma.Steam
string errorMsg;
if (!CheckWorkshopItemEnabled(item))
{
installedSuccessfully = EnableWorkShopItem(item, true, out errorMsg);
installedSuccessfully = EnableWorkShopItem(item, out errorMsg);
}
else if (!CheckWorkshopItemUpToDate(item))
{
@@ -1366,29 +1410,65 @@ namespace Barotrauma.Steam
if (!installedSuccessfully)
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }));
CrossThread.RequestExecutionOnMainThread(() =>
{
DebugConsole.NewMessage(errorMsg, Color.Red);
string errorId = errorMsg;
if (!GUIMessageBox.MessageBoxes.Any(m => m.UserData as string == errorId))
{
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg }))
{
UserData = errorId
};
}
});
}
else
{
//TODO: potential race condition
new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
updateNotifications.Add(TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title));
}
}
catch (Exception e)
{
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }));
GameAnalyticsManager.AddErrorEventOnce(
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
CrossThread.RequestExecutionOnMainThread(() =>
{
string errorId = e.Message;
if (!GUIMessageBox.MessageBoxes.Any(m => m.UserData as string == errorId))
{
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, e.Message + ", " + e.TargetSite }))
{
UserData = errorId
};
}
GameAnalyticsManager.AddErrorEventOnce(
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
});
}
}
if (updateNotifications.Count > 0)
{
CrossThread.RequestExecutionOnMainThread(() =>
{
while (updateNotifications.Count > 0)
{
float width = updateNotifications.Max(notif => GUI.Font.MeasureString(notif).X) * 1.25f;
int notificationsPerMsgBox = 20;
new GUIMessageBox("", string.Join('\n', updateNotifications.Take(notificationsPerMsgBox)),
relativeSize: new Microsoft.Xna.Framework.Vector2(0.25f, 0.0f),
minSize: new Microsoft.Xna.Framework.Point((int)width, 0));
updateNotifications.RemoveRange(0, Math.Min(notificationsPerMsgBox, updateNotifications.Count));
}
});
}
List<Task> tasks;
lock (modCopiesInProgress)
{
@@ -1403,16 +1483,20 @@ namespace Barotrauma.Steam
{
errorMsg = "";
if (!(item?.IsInstalled ?? false)) { return false; }
if (!DisableWorkShopItem(item, false, out errorMsg)) { return false; }
if (!EnableWorkShopItem(item, allowFileOverwrite: false, errorMsg: out errorMsg)) { return false; }
bool reenable = GameMain.Config.SelectedContentPackages.Any(p => !string.IsNullOrEmpty(p.SteamWorkshopUrl) && GetWorkshopItemIDFromUrl(p.SteamWorkshopUrl) == item?.Id);
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
{
if (!DisableWorkShopItem(item, false, out errorMsg)) { return false; }
}
if (!EnableWorkShopItem(item, errorMsg: out errorMsg, selectContentPackage: reenable)) { return false; }
return true;
}
private static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage)
{
string packageName = contentPackage.Name;
string packageName = contentPackage.Name.Trim();
packageName = ToolBox.RemoveInvalidFileNameChars(packageName);
while (packageName.Last() == '.') { packageName = packageName.Substring(0, packageName.Length-1); }
//packageName = packageName + "_" + GetWorkshopItemIDFromUrl(contentPackage.SteamWorkshopUrl);
return Path.Combine("Mods", packageName, MetadataFileName);
@@ -1429,7 +1513,9 @@ namespace Barotrauma.Steam
attr.Name.ToString() == "characterfile") &&
attr.Value.CleanUpPath().Contains("/"))
{
attr.Value = CorrectContentFilePath(attr.Value, package, true);
ContentType type = ContentType.None;
Enum.TryParse(attr.Name.LocalName, true, out type);
attr.Value = CorrectContentFilePath(attr.Value, type, package, true);
}
}
@@ -1441,18 +1527,20 @@ namespace Barotrauma.Steam
private static void CorrectContentFileCopy(ContentPackage package, string src, string dest, bool overwrite)
{
if (!overwrite && File.Exists(dest)) { return; }
if (Path.GetExtension(src).Equals(".xml", StringComparison.OrdinalIgnoreCase))
{
XDocument doc = XMLExtensions.TryLoadXml(src);
if (doc != null)
{
CorrectXMLFilePaths(package, doc.Root);
using (MemoryStream stream = new MemoryStream())
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
XmlWriterSettings settings = new XmlWriterSettings();
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Indent = true;
settings.Encoding = new System.Text.UTF8Encoding(false);
using (var xmlWriter = XmlWriter.Create(stream, settings))
using (var xmlWriter = System.Xml.XmlWriter.Create(stream, settings))
{
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
@@ -1463,23 +1551,29 @@ namespace Barotrauma.Steam
}
else
{
File.Copy(src, dest, overwrite: overwrite);
File.Copy(src, dest, overwrite: true);
}
}
else
{
File.Copy(src, dest, overwrite: overwrite);
File.Copy(src, dest, overwrite: true);
}
}
private static string CorrectContentFilePath(string contentFilePath, ContentPackage package, bool checkIfFileExists = false)
private static string CorrectContentFilePath(string contentFilePath, ContentType type, ContentPackage package, bool checkIfFileExists = false)
{
string packageName = Path.GetDirectoryName(GetWorkshopItemContentPackagePath(package));
contentFilePath = contentFilePath.CleanUpPathCrossPlatform();
if (checkIfFileExists && File.Exists(contentFilePath))
if (checkIfFileExists)
{
bool exists = File.Exists(contentFilePath);
if (type == ContentType.Executable ||
type == ContentType.ServerExecutable)
{
exists |= File.Exists(contentFilePath + ".dll");
}
return contentFilePath;
}
@@ -149,9 +149,15 @@ namespace Barotrauma.Networking
}
}
short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
short[] prevUncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
bool prevCaptured = true;
int captureTimer;
void UpdateCapture()
{
short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE];
Array.Copy(uncompressedBuffer, 0, prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
Array.Clear(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
while (capturing)
{
int alcError;
@@ -202,6 +208,21 @@ namespace Barotrauma.Networking
bool allowEnqueue = false;
if (GameMain.WindowActive)
{
ForceLocal = captureTimer > 0 ? ForceLocal : false;
bool pttDown = false;
if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) &&
GUI.KeyboardDispatcher.Subscriber == null)
{
pttDown = true;
if (PlayerInput.KeyDown(InputType.LocalVoice))
{
ForceLocal = true;
}
else
{
ForceLocal = false;
}
}
if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity)
{
if (dB > GameMain.Config.NoiseGateThreshold)
@@ -211,25 +232,38 @@ namespace Barotrauma.Networking
}
else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk)
{
if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null)
if (pttDown)
{
allowEnqueue = true;
}
}
}
if (allowEnqueue)
if (allowEnqueue || captureTimer > 0)
{
LastEnqueueAudio = DateTime.Now;
//encode audio and enqueue it
lock (buffers)
{
if (!prevCaptured) //enqueue the previous buffer if not sent to avoid cutoff
{
int compressedCountPrev = VoipConfig.Encoder.Encode(prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE);
EnqueueBuffer(compressedCountPrev);
}
int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE);
EnqueueBuffer(compressedCount);
}
captureTimer -= (VoipConfig.BUFFER_SIZE * 1000) / VoipConfig.FREQUENCY;
if (allowEnqueue)
{
captureTimer = GameMain.Config.VoiceChatCutoffPrevention;
}
prevCaptured = true;
}
else
{
captureTimer = 0;
prevCaptured = false;
//enqueue silence
lock (buffers)
{
@@ -241,14 +275,6 @@ namespace Barotrauma.Networking
}
}
public override void Write(IWriteMessage msg)
{
lock (buffers)
{
base.Write(msg);
}
}
public override void Dispose()
{
Instance = null;
@@ -85,11 +85,10 @@ namespace Barotrauma.Networking
return;
}
if (queue.Read(msg))
Client client = gameClient.ConnectedClients.Find(c => c.VoipQueue == queue);
if (queue.Read(msg, discardData: client.Muted || client.MutedLocally))
{
Client client = gameClient.ConnectedClients.Find(c => c.VoipQueue == queue);
if (client.Muted || client.MutedLocally) { return; }
if (client.VoipSound == null)
{
DebugConsole.Log("Recreating voipsound " + queueId);
@@ -98,7 +97,8 @@ namespace Barotrauma.Networking
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
{
var messageType = ChatMessage.CanUseRadio(client.Character, out WifiComponent radio) ? ChatMessageType.Radio : ChatMessageType.Default;
WifiComponent radio = null;
var messageType = !client.VoipQueue.ForceLocal && ChatMessage.CanUseRadio(client.Character, out radio) ? ChatMessageType.Radio : ChatMessageType.Default;
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio;
@@ -61,10 +61,10 @@ namespace Barotrauma
foreach (GUIComponent comp in listBox.Content.Children)
{
if (comp.FindChild("votes") is GUITextBlock voteText) comp.RemoveChild(voteText);
if (comp.FindChild("votes") is GUITextBlock voteText) { comp.RemoveChild(voteText); }
}
if (clients == null) return;
if (clients == null) { return; }
List<Pair<object, int>> voteList = GetVoteList(voteType, clients);
foreach (Pair<object, int> votable in voteList)
@@ -73,7 +73,7 @@ namespace Barotrauma
}
break;
case VoteType.StartRound:
if (clients == null) return;
if (clients == null) { return; }
foreach (Client client in clients)
{
var clientReady = GameMain.NetLobbyScreen.PlayerList.Content.FindChild(client)?.FindChild("clientready");
@@ -113,18 +113,18 @@ namespace Barotrauma
switch (voteType)
{
case VoteType.Sub:
Submarine sub = data as Submarine;
if (sub == null) return;
SubmarineInfo sub = data as SubmarineInfo;
if (sub == null) { return; }
msg.Write(sub.Info.Name);
msg.Write(sub.Name);
break;
case VoteType.Mode:
GameModePreset gameMode = data as GameModePreset;
if (gameMode == null) return;
if (gameMode == null) { return; }
msg.Write(gameMode.Identifier);
break;
case VoteType.EndRound:
if (!(data is bool)) return;
if (!(data is bool)) { return; }
msg.Write((bool)data);
break;
case VoteType.Kick:
@@ -153,12 +153,12 @@ namespace Barotrauma
{
int votes = inc.ReadByte();
string subName = inc.ReadString();
List<Submarine> serversubs = new List<Submarine>();
List<SubmarineInfo> serversubs = new List<SubmarineInfo>();
foreach (GUIComponent item in GameMain.NetLobbyScreen?.SubList?.Content?.Children)
{
if (item.UserData != null && item.UserData is Submarine) serversubs.Add(item.UserData as Submarine);
if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); }
}
Submarine sub = serversubs.FirstOrDefault(sm => sm.Info.Name == subName);
SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName);
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
}
}