Renamed project folders from Subsurface to Barotrauma

This commit is contained in:
Regalis
2017-06-04 15:00:53 +03:00
parent ad03c8bf0d
commit 94c6a8ea1b
697 changed files with 157 additions and 211 deletions
@@ -0,0 +1,409 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
namespace Barotrauma.Networking
{
class FileReceiver
{
public class FileTransferIn : IDisposable
{
public string FileName
{
get;
private set;
}
public string FilePath
{
get;
private set;
}
public ulong FileSize
{
get;
set;
}
public ulong Received
{
get;
private set;
}
public FileTransferType FileType
{
get;
private set;
}
public FileTransferStatus Status
{
get;
set;
}
public float BytesPerSecond
{
get;
private set;
}
public float Progress
{
get { return Received / (float)FileSize; }
}
public FileStream WriteStream
{
get;
private set;
}
public int TimeStarted
{
get;
private set;
}
public NetConnection Connection
{
get;
private set;
}
public int SequenceChannel;
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;
Status = FileTransferStatus.NotStarted;
}
public void ReadBytes(NetIncomingMessage inc)
{
byte[] all = inc.ReadBytes(inc.LengthBytes - inc.PositionInBytes);
Received += (ulong)all.Length;
WriteStream.Write(all, 0, all.Length);
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;
Status = Received >= FileSize ? FileTransferStatus.Finished : FileTransferStatus.Receiving;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (disposed) return;
if (disposing)
{
if (WriteStream != null)
{
WriteStream.Flush();
WriteStream.Close();
WriteStream.Dispose();
WriteStream = null;
}
}
disposed = true;
}
public void Dispose()
{
Dispose(true);
}
}
const int MaxFileSize = 1000000;
public delegate void OnFinishedDelegate(FileTransferIn fileStreamReceiver);
public OnFinishedDelegate OnFinished;
private List<FileTransferIn> activeTransfers;
private string downloadFolder;
public List<FileTransferIn> ActiveTransfers
{
get { return activeTransfers; }
}
public FileReceiver(string downloadFolder)
{
if (GameMain.Server != null)
{
throw new InvalidOperationException("Creating a file receiver is not allowed when a server is running.");
}
activeTransfers = new List<FileTransferIn>();
this.downloadFolder = downloadFolder;
}
public void ReadMessage(NetIncomingMessage inc)
{
if (GameMain.Server != null)
{
throw new InvalidOperationException("Receiving files when a server is running is not allowed");
}
System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
t.Status == FileTransferStatus.Error ||
t.Status == FileTransferStatus.Canceled ||
t.Status == FileTransferStatus.Finished), "List of active file transfers contains entires that should have been removed");
byte transferMessageType = inc.ReadByte();
switch (transferMessageType)
{
case (byte)FileTransferMessageType.Initiate:
var existingTransfer = activeTransfers.Find(t => t.SequenceChannel == inc.SequenceChannel);
if (existingTransfer != null)
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer error: file transfer initiated on a sequence channel that's already in use");
return;
}
byte fileType = inc.ReadByte();
ushort chunkLen = inc.ReadUInt16();
ulong fileSize = inc.ReadUInt64();
string fileName = inc.ReadString();
string errorMsg;
if (!ValidateInitialData(fileType, fileName, fileSize, out errorMsg))
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");
return;
}
if (GameSettings.VerboseLogging)
{
DebugConsole.Log("Received file transfer initiation message: ");
DebugConsole.Log(" File: "+fileName);
DebugConsole.Log(" Size: " + fileSize);
DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel);
}
if (!Directory.Exists(downloadFolder))
{
try
{
Directory.CreateDirectory(downloadFolder);
}
catch (Exception e)
{
DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \""+downloadFolder+"\".", e);
return;
}
}
var newTransfer = new FileTransferIn(inc.SenderConnection, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType);
newTransfer.SequenceChannel = inc.SequenceChannel;
newTransfer.Status = FileTransferStatus.Receiving;
newTransfer.FileSize = fileSize;
activeTransfers.Add(newTransfer);
break;
case (byte)FileTransferMessageType.Data:
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == inc.SequenceChannel);
if (activeTransfer == null)
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
return;
}
if (activeTransfer.Received + (ulong)(inc.LengthBytes-inc.PositionInBytes) > activeTransfer.FileSize)
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer error: Received more data than expected");
activeTransfer.Status = FileTransferStatus.Error;
StopTransfer(activeTransfer);
return;
}
try
{
activeTransfer.ReadBytes(inc);
}
catch (Exception e)
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer error: "+e.Message);
activeTransfer.Status = FileTransferStatus.Error;
StopTransfer(activeTransfer, true);
return;
}
if (activeTransfer.Status == FileTransferStatus.Finished)
{
activeTransfer.Dispose();
string errorMessage = "";
if (ValidateReceivedData(activeTransfer, out errorMessage))
{
OnFinished(activeTransfer);
StopTransfer(activeTransfer);
}
else
{
new GUIMessageBox("File transfer aborted", errorMessage);
activeTransfer.Status = FileTransferStatus.Error;
StopTransfer(activeTransfer, true);
}
}
break;
case (byte)FileTransferMessageType.Cancel:
byte sequenceChannel = inc.ReadByte();
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
if (matchingTransfer != null)
{
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
StopTransfer(matchingTransfer);
}
break;
}
}
private bool ValidateInitialData(byte type, string fileName, ulong fileSize, out string errorMessage)
{
errorMessage = "";
if (fileSize > MaxFileSize)
{
errorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")";
return false;
}
if (!Enum.IsDefined(typeof(FileTransferType), (int)type))
{
errorMessage = "Unknown file type";
return false;
}
if (string.IsNullOrEmpty(fileName) ||
fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1)
{
errorMessage = "Illegal characters in file name ''" + fileName + "''";
return false;
}
switch (type)
{
case (byte)FileTransferType.Submarine:
if (Path.GetExtension(fileName) != ".sub")
{
errorMessage = "Wrong file extension ''" + Path.GetExtension(fileName) + "''! (Expected .sub)";
return false;
}
break;
}
return true;
}
private bool ValidateReceivedData(FileTransferIn fileTransfer, out string ErrorMessage)
{
ErrorMessage = "";
switch (fileTransfer.FileType)
{
case FileTransferType.Submarine:
Stream stream = null;
try
{
stream = SaveUtil.DecompressFiletoStream(fileTransfer.FilePath);
}
catch (Exception e)
{
ErrorMessage = "Loading received submarine ''" + fileTransfer.FileName + "'' failed! {" + e.Message + "}";
return false;
}
if (stream == null)
{
ErrorMessage = "Decompressing received submarine file''" + fileTransfer.FilePath + "'' failed!";
return false;
}
try
{
stream.Position = 0;
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.IgnoreProcessingInstructions = true;
using (var reader = XmlReader.Create(stream, settings))
{
while (reader.Read());
}
}
catch
{
stream.Close();
stream.Dispose();
ErrorMessage = "Parsing file ''" + fileTransfer.FilePath + "'' failed! The file may not be a valid submarine file.";
return false;
}
stream.Close();
stream.Dispose();
break;
}
return true;
}
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
{
File.Delete(transfer.FilePath);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to delete file \""+transfer.FilePath+"\" ("+e.Message+")");
}
}
}
}
}
@@ -0,0 +1,286 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma.Networking
{
enum FileTransferStatus
{
NotStarted, Sending, Receiving, Finished, Canceled, Error
}
enum FileTransferMessageType
{
Unknown, Initiate, Data, Cancel
}
enum FileTransferType
{
Submarine
}
class FileSender
{
public class FileTransferOut
{
private byte[] data;
private DateTime startingTime;
private NetConnection connection;
public FileTransferStatus Status;
public string FileName
{
get;
private set;
}
public string FilePath
{
get;
private set;
}
public FileTransferType FileType
{
get;
private set;
}
public float Progress
{
get { return SentOffset / (float)Data.Length; }
}
public float WaitTimer
{
get;
set;
}
public byte[] Data
{
get { return data; }
}
public int SentOffset
{
get;
set;
}
public NetConnection Connection
{
get { return connection; }
}
public int SequenceChannel;
public FileTransferOut(NetConnection recipient, FileTransferType fileType, string filePath)
{
connection = recipient;
FileType = fileType;
FilePath = filePath;
FileName = Path.GetFileName(filePath);
Status = FileTransferStatus.NotStarted;
startingTime = DateTime.Now;
data = File.ReadAllBytes(filePath);
}
}
const int MaxTransferCount = 16;
const int MaxTransferCountPerRecipient = 5;
public static TimeSpan MaxTransferDuration = new TimeSpan(0, 2, 0);
public delegate void FileTransferDelegate(FileTransferOut fileStreamReceiver);
public FileTransferDelegate OnStarted;
public FileTransferDelegate OnEnded;
private List<FileTransferOut> activeTransfers;
private int chunkLen;
private NetPeer peer;
public List<FileTransferOut> ActiveTransfers
{
get { return activeTransfers; }
}
public FileSender(NetworkMember networkMember)
{
peer = networkMember.netPeer;
chunkLen = peer.Configuration.MaximumTransmissionUnit - 100;
activeTransfers = new List<FileTransferOut>();
}
public FileTransferOut StartTransfer(NetConnection recipient, FileTransferType fileType, string filePath)
{
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.");
return null;
}
FileTransferOut transfer = null;
try
{
transfer = new FileTransferOut(recipient, fileType, filePath);
transfer.SequenceChannel = 1;
while (activeTransfers.Any(t => t.Connection == recipient && t.SequenceChannel == transfer.SequenceChannel))
{
transfer.SequenceChannel++;
}
activeTransfers.Add(transfer);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to initiate file transfer", e);
}
OnStarted(transfer);
return transfer;
}
public void Update(float deltaTime)
{
activeTransfers.RemoveAll(t => t.Connection.Status != NetConnectionStatus.Connected);
var endedTransfers = activeTransfers.FindAll(t =>
t.Connection.Status != NetConnectionStatus.Connected ||
t.Status == FileTransferStatus.Finished ||
t.Status == FileTransferStatus.Canceled ||
t.Status == FileTransferStatus.Error);
foreach (FileTransferOut transfer in endedTransfers)
{
activeTransfers.Remove(transfer);
OnEnded(transfer);
}
foreach (FileTransferOut transfer in activeTransfers)
{
transfer.WaitTimer -= deltaTime;
if (transfer.WaitTimer > 0.0f) continue;
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, 1)) continue;
transfer.WaitTimer = transfer.Connection.AverageRoundtripTime;
// send another part of the file
long remaining = transfer.Data.Length - transfer.SentOffset;
int sendByteCount = (remaining > chunkLen ? chunkLen : (int)remaining);
NetOutgoingMessage message;
//first message; send length, chunk length, file name etc
if (transfer.SentOffset == 0)
{
message = peer.CreateMessage();
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
message.Write((byte)FileTransferMessageType.Initiate);
message.Write((byte)transfer.FileType);
message.Write((ushort)chunkLen);
message.Write((ulong)transfer.Data.Length);
message.Write(transfer.FileName);
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(1 + 1 + sendByteCount);
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
message.Write((byte)FileTransferMessageType.Data);
byte[] sendBytes = new byte[sendByteCount];
Array.Copy(transfer.Data, transfer.SentOffset, sendBytes, 0, sendByteCount);
message.Write(sendBytes);
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;
}
}
}
public void CancelTransfer(FileTransferOut transfer)
{
transfer.Status = FileTransferStatus.Canceled;
activeTransfers.Remove(transfer);
OnEnded(transfer);
GameMain.Server.SendCancelTransferMsg(transfer);
}
public void ReadFileRequest(NetIncomingMessage inc)
{
byte messageType = inc.ReadByte();
if (messageType == (byte)FileTransferMessageType.Cancel)
{
byte sequenceChannel = inc.ReadByte();
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
if (matchingTransfer != null) CancelTransfer(matchingTransfer);
return;
}
byte fileType = inc.ReadByte();
switch (fileType)
{
case (byte)FileTransferType.Submarine:
string fileName = inc.ReadString();
string fileHash = inc.ReadString();
var requestedSubmarine = Submarine.SavedSubmarines.Find(s => s.Name == fileName && s.MD5Hash.Hash == fileHash);
if (requestedSubmarine != null)
{
StartTransfer(inc.SenderConnection, FileTransferType.Submarine, requestedSubmarine.FilePath);
}
break;
}
}
}
}