Some more logic to handle missing sub files and active file transfers when starting a round:

- server waits for transfers to finish before starting the round (up to a max 20 seconds, can be skipped by the host)
- clients enable the spectate button when the round starts (in case they fail to start the round due to a missing sub file or an error)
- clients notify the server if a transfer is cancelled

+ FileReceivers can't be instantiated if a server is running
This commit is contained in:
Regalis
2017-03-09 19:56:27 +02:00
parent ca402396a0
commit e406b76cd5
5 changed files with 67 additions and 12 deletions
@@ -154,6 +154,11 @@ namespace Barotrauma.Networking
public FileReceiver(string downloadFolder) 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>(); activeTransfers = new List<FileTransferIn>();
this.downloadFolder = downloadFolder; this.downloadFolder = downloadFolder;
@@ -161,6 +166,11 @@ namespace Barotrauma.Networking
public void ReadMessage(NetIncomingMessage inc) 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 => System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
t.Status == FileTransferStatus.Error || t.Status == FileTransferStatus.Error ||
t.Status == FileTransferStatus.Canceled || t.Status == FileTransferStatus.Canceled ||
@@ -109,6 +109,11 @@ namespace Barotrauma.Networking
private NetPeer peer; private NetPeer peer;
public List<FileTransferOut> ActiveTransfers
{
get { return activeTransfers; }
}
public FileSender(NetworkMember networkMember) public FileSender(NetworkMember networkMember)
{ {
peer = networkMember.netPeer; peer = networkMember.netPeer;
+17 -3
View File
@@ -629,6 +629,10 @@ namespace Barotrauma.Networking
{ {
if (Character != null) Character.Remove(); if (Character != null) Character.Remove();
//enable spectate button in case we fail to start the round now
//(for example, due to a missing sub file or an error)
GameMain.NetLobbyScreen.ShowSpectateButton();
Entity.Spawner.Clear(); Entity.Spawner.Clear();
entityEventManager.Clear(); entityEventManager.Clear();
LastSentEntityEventID = 0; LastSentEntityEventID = 0;
@@ -999,6 +1003,15 @@ namespace Barotrauma.Networking
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
} }
public void CancelFileTransfer(FileReceiver.FileTransferIn transfer)
{
NetOutgoingMessage msg = client.CreateMessage();
msg.Write((byte)ClientPacketHeader.FILE_REQUEST);
msg.Write((byte)FileTransferMessageType.Cancel);
msg.Write((byte)transfer.SequenceChannel);
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
}
private void OnFileReceived(FileReceiver.FileTransferIn transfer) private void OnFileReceived(FileReceiver.FileTransferIn transfer)
{ {
new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully."); new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully.");
@@ -1062,8 +1075,9 @@ namespace Barotrauma.Networking
MathUtils.GetBytesReadable((long)transfer.Received) + " / " + MathUtils.GetBytesReadable((long)transfer.FileSize), MathUtils.GetBytesReadable((long)transfer.Received) + " / " + MathUtils.GetBytesReadable((long)transfer.FileSize),
Color.White, null, 0, GUI.SmallFont); 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))) if (GUI.DrawButton(spriteBatch, new Rectangle((int)pos.X + 140, (int)pos.Y + 18, 60, 15), "Cancel", new Color(0.47f, 0.13f, 0.15f, 0.08f)))
{ {
CancelFileTransfer(transfer);
fileReceiver.StopTransfer(transfer); fileReceiver.StopTransfer(transfer);
} }
@@ -1214,8 +1228,8 @@ namespace Barotrauma.Networking
NetOutgoingMessage readyToStartMsg = client.CreateMessage(); NetOutgoingMessage readyToStartMsg = client.CreateMessage();
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME); readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
//correct sub & shuttle files found //assume we have the required sub files to start the round
//TODO: check if they're actually found //(if not, we'll find out when the server sends the STARTGAME message and can initiate a file transfer)
readyToStartMsg.Write(true); readyToStartMsg.Write(true);
WriteCharacterInfo(readyToStartMsg); WriteCharacterInfo(readyToStartMsg);
+20 -2
View File
@@ -982,14 +982,32 @@ namespace Barotrauma.Networking
server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0); server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0);
//give the clients a few seconds to request missing sub/shuttle files before starting the round //give the clients a few seconds to request missing sub/shuttle files before starting the round
float waitForResponseTimer = 3.0f; float waitForResponseTimer = 5.0f;
while (connectedClients.Any(c => !c.ReadyToStart) && waitForResponseTimer > 0.0f) while (connectedClients.Any(c => !c.ReadyToStart) && waitForResponseTimer > 0.0f)
{ {
waitForResponseTimer -= CoroutineManager.UnscaledDeltaTime; waitForResponseTimer -= CoroutineManager.UnscaledDeltaTime;
yield return CoroutineStatus.Running; yield return CoroutineStatus.Running;
} }
//todo: wait until file transfers are finished/cancelled if (fileSender.ActiveTransfers.Count > 0)
{
var msgBox = new GUIMessageBox("", "Waiting for file transfers to finish before starting the round...", new string[] { "Start now" });
msgBox.Buttons[0].OnClicked += msgBox.Close;
float waitForTransfersTimer = 20.0f;
while (fileSender.ActiveTransfers.Count > 0 && waitForTransfersTimer > 0.0f)
{
waitForTransfersTimer -= CoroutineManager.UnscaledDeltaTime;
//message box close, break and start the round immediately
if (!GUIMessageBox.MessageBoxes.Contains(msgBox))
{
break;
}
yield return CoroutineStatus.Running;
}
}
} }
GameMain.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode), false); GameMain.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode), false);
+14 -6
View File
@@ -473,6 +473,16 @@ namespace Barotrauma
base.Select(); base.Select();
} }
public void ShowSpectateButton()
{
if (GameMain.Client == null) return;
infoFrame.RemoveChild(infoFrame.children.Find(c => c.UserData as string == "spectateButton"));
GUIButton spectateButton = new GUIButton(new Rectangle(0, 0, 80, 30), "Spectate", Alignment.BottomRight, GUI.Style, infoFrame);
spectateButton.OnClicked = GameMain.Client.SpectateClicked;
spectateButton.UserData = "spectateButton";
}
private void UpdatePlayerFrame(CharacterInfo characterInfo) private void UpdatePlayerFrame(CharacterInfo characterInfo)
{ {
if (myPlayerFrame.children.Count <= 1) if (myPlayerFrame.children.Count <= 1)
@@ -1227,16 +1237,14 @@ namespace Barotrauma
errorMsg += "Do you want to download the file from the server host?"; errorMsg += "Do you want to download the file from the server host?";
if (GUIMessageBox.MessageBoxes.Count > 0) //already showing a message about the same sub
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
{ {
var currentMessageBox = GUIMessageBox.VisibleBox; return false;
if (currentMessageBox != null && currentMessageBox.UserData as string == subName)
{
return false;
}
} }
var requestFileBox = new GUIMessageBox("Submarine not found!", errorMsg, new string[] { "Yes", "No" }, 400, 300); var requestFileBox = new GUIMessageBox("Submarine not found!", errorMsg, new string[] { "Yes", "No" }, 400, 300);
requestFileBox.UserData = "request" + subName;
requestFileBox.Buttons[0].UserData = subName; requestFileBox.Buttons[0].UserData = subName;
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close; requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) => requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>