diff --git a/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs b/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs index 0608df673..40d499b0d 100644 --- a/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs +++ b/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs @@ -73,13 +73,21 @@ namespace Barotrauma.Networking private set; } + public NetConnection Connection + { + get; + private set; + } + public int SequenceChannel; - public FileTransferIn(string filePath, FileTransferType fileType) + public FileTransferIn(NetConnection connection, string filePath, FileTransferType fileType) { FilePath = filePath; FileName = Path.GetFileName(FilePath); FileType = fileType; + + Connection = connection; WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None); TimeStarted = Environment.TickCount; @@ -95,6 +103,11 @@ namespace Barotrauma.Networking int passed = Environment.TickCount - TimeStarted; float psec = passed / 1000.0f; + + if (GameSettings.VerboseLogging) + { + DebugConsole.Log("Received "+all.Length+" bytes of the file "+FileName+" ("+Received+"/"+FileSize+" received)"); + } BytesPerSecond = Received / psec; @@ -176,7 +189,15 @@ namespace Barotrauma.Networking return; } - var newTransfer = new FileTransferIn(Path.Combine(downloadFolder, fileName), (FileTransferType)fileType); + if (GameSettings.VerboseLogging) + { + DebugConsole.Log("Received file transfer initiation message: "); + DebugConsole.Log(" File: "+fileName); + DebugConsole.Log(" Size: " + fileSize); + DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel); + } + + var newTransfer = new FileTransferIn(inc.SenderConnection, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType); newTransfer.SequenceChannel = inc.SequenceChannel; newTransfer.Status = FileTransferStatus.Receiving; newTransfer.FileSize = fileSize; @@ -185,7 +206,7 @@ namespace Barotrauma.Networking break; case (byte)FileTransferMessageType.Data: - var activeTransfer = activeTransfers.Find(t => t.SequenceChannel == inc.SequenceChannel); + var activeTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == inc.SequenceChannel); if (activeTransfer == null) { DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message"); @@ -231,6 +252,12 @@ namespace Barotrauma.Networking } } + break; + case (byte)FileTransferMessageType.Cancel: + byte sequenceChannel = inc.ReadByte(); + var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel); + if (matchingTransfer != null) StopTransfer(matchingTransfer); + break; } } diff --git a/Subsurface/Source/Networking/FileTransfer/FileSender.cs b/Subsurface/Source/Networking/FileTransfer/FileSender.cs index c620efd27..1517cb215 100644 --- a/Subsurface/Source/Networking/FileTransfer/FileSender.cs +++ b/Subsurface/Source/Networking/FileTransfer/FileSender.cs @@ -98,6 +98,9 @@ namespace Barotrauma.Networking } } + const int MaxTransferCount = 16; + const int MaxTransferCountPerRecipient = 5; + public static TimeSpan MaxTransferDuration = new TimeSpan(0, 2, 0); private List activeTransfers; @@ -116,7 +119,16 @@ namespace Barotrauma.Networking public FileTransferOut StartTransfer(NetConnection recipient, FileTransferType fileType, string filePath) { - //TODO: set a limit on the amount of active transfers + if (activeTransfers.Count >= MaxTransferCount) + { + return null; + } + + if (activeTransfers.Count(t => t.Connection == recipient) > MaxTransferCountPerRecipient) + { + return null; + } + if (!File.Exists(filePath)) { DebugConsole.ThrowError("Failed to initiate file transfer (file \""+filePath+"\" not found."); @@ -149,7 +161,7 @@ namespace Barotrauma.Networking foreach (FileTransferOut transfer in activeTransfers) { transfer.WaitTimer -= deltaTime; - if (transfer.WaitTimer > 0.0f) return; + if (transfer.WaitTimer > 0.0f) continue; if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, 1)) continue; @@ -164,7 +176,7 @@ namespace Barotrauma.Networking //first message; send length, chunk length, file name etc if (transfer.SentOffset == 0) { - message = peer.CreateMessage(sendByteCount + 8 + 1); + message = peer.CreateMessage(); message.Write((byte)ServerPacketHeader.FILE_TRANSFER); message.Write((byte)FileTransferMessageType.Initiate); message.Write((byte)transfer.FileType); @@ -174,9 +186,17 @@ namespace Barotrauma.Networking transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel); transfer.Status = FileTransferStatus.Sending; + + if (GameSettings.VerboseLogging) + { + DebugConsole.Log("Sending file transfer initiation message: "); + DebugConsole.Log(" File: " + transfer.FileName); + DebugConsole.Log(" Size: " + transfer.Data.Length); + DebugConsole.Log(" Sequence channel: " + transfer.SequenceChannel); + } } - message = peer.CreateMessage(sendByteCount + 8 + 1); + message = peer.CreateMessage(1 + 1 + sendByteCount); message.Write((byte)ServerPacketHeader.FILE_TRANSFER); message.Write((byte)FileTransferMessageType.Data); @@ -187,7 +207,12 @@ namespace Barotrauma.Networking transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel); transfer.SentOffset += sendByteCount; - + + if (GameSettings.VerboseLogging) + { + DebugConsole.Log("Sending " + sendByteCount + " bytes of the file " + transfer.FileName + " (" + transfer.SentOffset + "/" + transfer.Data.Length + " sent)"); + } + if (remaining - sendByteCount <= 0) { transfer.Status = FileTransferStatus.Finished; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 07efd1caa..e37f7a63f 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -1036,7 +1036,41 @@ namespace Barotrauma.Networking public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) { base.Draw(spriteBatch); - + + if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0) + { + Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - 35); + + GUI.DrawRectangle(spriteBatch, new Rectangle( + (int)pos.X, + (int)pos.Y, + fileReceiver.ActiveTransfers.Count * 210 + 10, + 32), + Color.Black * 0.8f, true); + + for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++) + { + var transfer = fileReceiver.ActiveTransfers[i]; + + GameMain.NetLobbyScreen.SubList.children.Find(c => c is GUITextBlock && ((GUITextBlock)c).Text == transfer.FileName); + GUI.DrawString(spriteBatch, + pos, + ToolBox.LimitString("Downloading " + transfer.FileName, GUI.SmallFont, 200), + Color.White, null, 0, GUI.SmallFont); + GUI.DrawProgressBar(spriteBatch, new Vector2(pos.X, -pos.Y - 15), new Vector2(135, 15), transfer.Progress, Color.Green); + GUI.DrawString(spriteBatch, pos + new Vector2(5, 15), + MathUtils.GetBytesReadable((long)transfer.Received) + " / " + MathUtils.GetBytesReadable((long)transfer.FileSize), + Color.White, null, 0, GUI.SmallFont); + + if (GUI.DrawButton(spriteBatch, new Rectangle((int)pos.X + 140, (int)pos.Y + 15, 60, 15), "Cancel", new Color(0.47f, 0.13f, 0.15f, 0.08f))) + { + fileReceiver.StopTransfer(transfer); + } + + pos.X += 210; + } + } + if (!GameMain.DebugDraw) return; int width = 200, height = 300;