diff --git a/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs b/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs index 82f1241b2..0608df673 100644 --- a/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs +++ b/Subsurface/Source/Networking/FileTransfer/FileReceiver.cs @@ -13,10 +13,7 @@ namespace Barotrauma.Networking class FileReceiver { public class FileTransferIn : IDisposable - { - public delegate void OnFinishedDelegate(FileTransferIn fileStreamReceiver); - public OnFinishedDelegate OnFinished; - + { public string FileName { get; @@ -32,7 +29,7 @@ namespace Barotrauma.Networking public ulong FileSize { get; - private set; + set; } public ulong Received @@ -78,14 +75,12 @@ namespace Barotrauma.Networking public int SequenceChannel; - public FileTransferIn(string filePath, FileTransferType fileType, OnFinishedDelegate onFinished) + public FileTransferIn(string filePath, FileTransferType fileType) { FilePath = filePath; FileName = Path.GetFileName(FilePath); FileType = fileType; - - this.OnFinished = onFinished; - + WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None); TimeStarted = Environment.TickCount; @@ -131,11 +126,19 @@ namespace Barotrauma.Networking } const int MaxFileSize = 1000000; + + public delegate void OnFinishedDelegate(FileTransferIn fileStreamReceiver); + public OnFinishedDelegate OnFinished; private List activeTransfers; private string downloadFolder; + public List ActiveTransfers + { + get { return activeTransfers; } + } + public FileReceiver(string downloadFolder) { activeTransfers = new List(); @@ -143,7 +146,7 @@ namespace Barotrauma.Networking this.downloadFolder = downloadFolder; } - private void ReadMessage(NetIncomingMessage inc) + public void ReadMessage(NetIncomingMessage inc) { System.Diagnostics.Debug.Assert(!activeTransfers.Any(t => t.Status == FileTransferStatus.Error || @@ -173,9 +176,10 @@ namespace Barotrauma.Networking return; } - var newTransfer = new FileTransferIn(Path.Combine(downloadFolder, fileName), (FileTransferType)fileType, null); + var newTransfer = new FileTransferIn(Path.Combine(downloadFolder, fileName), (FileTransferType)fileType); newTransfer.SequenceChannel = inc.SequenceChannel; newTransfer.Status = FileTransferStatus.Receiving; + newTransfer.FileSize = fileSize; activeTransfers.Add(newTransfer); @@ -188,10 +192,11 @@ namespace Barotrauma.Networking return; } - if (activeTransfer.Received + (ulong)inc.LengthBytes > activeTransfer.FileSize * 1.1f) + if (activeTransfer.Received + (ulong)(inc.LengthBytes-inc.PositionInBytes) > activeTransfer.FileSize) { DebugConsole.ThrowError("File transfer error: Received more data than expected"); - activeTransfer.Status = FileTransferStatus.Error; + activeTransfer.Status = FileTransferStatus.Error; + StopTransfer(activeTransfer); return; } @@ -209,14 +214,18 @@ namespace Barotrauma.Networking if (activeTransfer.Status == FileTransferStatus.Finished) { + activeTransfer.Dispose(); + string errorMessage = ""; if (ValidateReceivedData(activeTransfer, out errorMessage)) { - activeTransfer.OnFinished(activeTransfer); + OnFinished(activeTransfer); StopTransfer(activeTransfer); } else { + new GUIMessageBox("File transfer aborted", errorMessage); + activeTransfer.Status = FileTransferStatus.Error; StopTransfer(activeTransfer, true); } @@ -236,7 +245,7 @@ namespace Barotrauma.Networking return false; } - if (!Enum.IsDefined(typeof(FileTransferType), type)) + if (!Enum.IsDefined(typeof(FileTransferType), (int)type)) { errorMessage = "Unknown file type"; return false; @@ -318,6 +327,15 @@ namespace Barotrauma.Networking public void StopTransfer(FileTransferIn transfer, bool deleteFile = false) { + if (transfer.Status != FileTransferStatus.Finished && + transfer.Status != FileTransferStatus.Error) + { + transfer.Status = FileTransferStatus.Canceled; + } + + if (activeTransfers.Contains(transfer)) activeTransfers.Remove(transfer); + transfer.Dispose(); + if (deleteFile && File.Exists(transfer.FilePath)) { try @@ -329,15 +347,6 @@ namespace Barotrauma.Networking DebugConsole.ThrowError("Failed to delete file \""+transfer.FilePath+"\" ("+e.Message+")"); } } - - if (transfer.Status != FileTransferStatus.Finished && - transfer.Status != FileTransferStatus.Error) - { - transfer.Status = FileTransferStatus.Canceled; - } - - if (activeTransfers.Contains(transfer)) activeTransfers.Remove(transfer); - transfer.Dispose(); } } } diff --git a/Subsurface/Source/Networking/FileTransfer/FileSender.cs b/Subsurface/Source/Networking/FileTransfer/FileSender.cs index e020575c5..c620efd27 100644 --- a/Subsurface/Source/Networking/FileTransfer/FileSender.cs +++ b/Subsurface/Source/Networking/FileTransfer/FileSender.cs @@ -132,6 +132,7 @@ namespace Barotrauma.Networking { transfer.SequenceChannel++; } + activeTransfers.Add(transfer); } catch (Exception e) { @@ -173,7 +174,6 @@ namespace Barotrauma.Networking transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel); transfer.Status = FileTransferStatus.Sending; - continue; } message = peer.CreateMessage(sendByteCount + 8 + 1); diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index d9163370a..07efd1caa 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -43,6 +43,8 @@ namespace Barotrauma.Networking private ClientEntityEventManager entityEventManager; + private FileReceiver fileReceiver; + public byte ID { get { return myID; } @@ -55,6 +57,11 @@ namespace Barotrauma.Networking return otherClients; } } + + public FileReceiver FileReceiver + { + get { return fileReceiver; } + } public GameClient(string newName) { @@ -83,6 +90,9 @@ namespace Barotrauma.Networking name = newName; entityEventManager = new ClientEntityEventManager(this); + + fileReceiver = new FileReceiver("Submarines/Downloaded"); + fileReceiver.OnFinished += OnFileReceived; characterInfo = new CharacterInfo(Character.HumanConfigFile, name); characterInfo.Job = null; @@ -542,6 +552,9 @@ namespace Barotrauma.Networking case ServerPacketHeader.PERMISSIONS: ReadPermissions(inc); break; + case ServerPacketHeader.FILE_TRANSFER: + fileReceiver.ReadMessage(inc); + break; } break; case NetIncomingMessageType.StatusChanged: @@ -976,6 +989,40 @@ namespace Barotrauma.Networking chatMsgQueue.Add(chatMessage); } + public void RequestFile(string file, FileTransferType fileType) + { + NetOutgoingMessage msg = client.CreateMessage(); + msg.Write((byte)ClientPacketHeader.FILE_REQUEST); + msg.Write((byte)FileTransferMessageType.Initiate); + msg.Write((byte)fileType); + msg.Write(file); + client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); + } + + private void OnFileReceived(FileReceiver.FileTransferIn transfer) + { + new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully."); + switch (transfer.FileType) + { + case FileTransferType.Submarine: + Submarine.SavedSubmarines.RemoveAll(s => s.Name + ".sub" == transfer.FileName); + for (int i = 0; i < 2; i++) + { + var textBlock = ((i == 0) ? + GameMain.NetLobbyScreen.ShuttleList.ListBox.children.Find(c => (c.UserData as Submarine).Name + ".sub" == transfer.FileName) : + GameMain.NetLobbyScreen.SubList.children.Find(c => (c.UserData as Submarine).Name + ".sub" == transfer.FileName)) as GUITextBlock; + + if (textBlock == null) continue; + textBlock.TextColor = Color.White; + var newSub = new Submarine(transfer.FilePath); + Submarine.SavedSubmarines.Add(newSub); + textBlock.UserData = newSub; + textBlock.ToolTip = newSub.Description; + } + break; + } + } + public void CreateEntityEvent(IClientSerializable entity, object[] extraData) { entityEventManager.CreateEvent(entity, extraData); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 0007d8198..104b87252 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -134,8 +134,6 @@ namespace Barotrauma.Networking entityEventManager = new ServerEntityEventManager(this); - fileSender = new FileSender(this); - whitelist = new WhiteList(); banList = new BanList(); @@ -155,6 +153,8 @@ namespace Barotrauma.Networking Log("Starting the server...", Color.Cyan); server = new NetServer(config); netPeer = server; + fileSender = new FileSender(this); + server.Start(); } catch (Exception e) @@ -558,7 +558,7 @@ namespace Barotrauma.Networking case ClientPacketHeader.FILE_REQUEST: if (AllowFileTransfers) { - + fileSender.ReadFileRequest(inc); } break; } diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 197a253e3..ee4b9f324 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -1188,8 +1188,13 @@ namespace Barotrauma public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList) { + if (GameMain.Client == null) return false; + //already downloading the selected sub file - //if (GameMain.Client.ActiveFileTransferName == subName+".sub") return false; + if (GameMain.Client.FileReceiver.ActiveTransfers.Any(t => t.FileName == subName + ".sub")) + { + return false; + } var matchingListSub = subList.children.Find(c => c.UserData != null && (c.UserData as Submarine).Name == subName) as GUITextBlock; if (matchingListSub != null) @@ -1219,12 +1224,10 @@ namespace Barotrauma + "Your MD5 hash: " + sub.MD5Hash.Hash + " \n" + "Server's MD5 hash: " + md5Hash + ". "; } - - /*string downloadMsg = string.IsNullOrEmpty(GameMain.Client.ActiveFileTransferName) ? - "Do you want to download the file from the server host?" : - "Do you want to download the file and cancel downloading ''" + GameMain.Client.ActiveFileTransferName + "''?";*/ - if (GUIMessageBox.MessageBoxes.Count>0) + errorMsg += "Do you want to download the file from the server host?"; + + if (GUIMessageBox.MessageBoxes.Count > 0) { var currentMessageBox = GUIMessageBox.VisibleBox; if (currentMessageBox != null && currentMessageBox.UserData as string == subName) @@ -1233,15 +1236,15 @@ namespace Barotrauma } } - /*var requestFileBox = new GUIMessageBox("Submarine not found!", errorMsg+downloadMsg, new string[] { "Yes", "No" }, 400, 300); + var requestFileBox = new GUIMessageBox("Submarine not found!", errorMsg, new string[] { "Yes", "No" }, 400, 300); requestFileBox.Buttons[0].UserData = subName; requestFileBox.Buttons[0].OnClicked += requestFileBox.Close; requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) => { - GameMain.Client.RequestFile(userdata.ToString(), FileTransferMessageType.Submarine); + GameMain.Client.RequestFile(userdata.ToString(), FileTransferType.Submarine); return true; }; - requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;*/ + requestFileBox.Buttons[1].OnClicked += requestFileBox.Close; return false; }