Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs
T
Joonas Rikkonen 58c92888b7 2ad9b5d...2f107db
commit 2f107db0475bf4b9a8b6f405b9ce8ec489cbc0ba
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 16:30:24 2019 +0200

    Another nullref fix to the OpenHealthWindow property setter. Closes #1090

commit 1d15d18d2501bedaa1b42ac8e0e7e09e2600960e
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 16:19:05 2019 +0200

    Fixed crashing when an incompatible content package is selected in config.xml or if the content package cannot be found. Happened because the game attempted to use TextManager.Get before text files had been loaded. Partially fixes #1093

commit 9ec1980fe90bcae65333c188b265ba16a6db6c05
Author: ezjamsen <ezjames.fi@gmail.com>
Date:   Thu Feb 7 16:16:53 2019 +0200

    added correct effects for alien blood

commit b6d2c56910b5d58477703abc6785ef80719a89a6
Author: ezjamsen <ezjames.fi@gmail.com>
Date:   Thu Feb 7 15:41:25 2019 +0200

    adjustments to fent, glue and antibiotics

commit 8df16acdaac0a521fe09fb62c6815a46a87f6f25
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 15:30:51 2019 +0200

    More descriptive ping exception error messages (only shown in debug builds now), some extra checks to prevent using the workshop without steam (although the checks that actually matter are implemented at Steam's side now)

commit 959c503c140196287ab60ec2357feb8bd5c85b18
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 14:00:48 2019 +0200

    Don't allow severing the joint between a moloch's shell and the "bladder"

commit 0c0b033016c2e82b8cf1b5a4e3f6faa9cde39f40
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 13:51:58 2019 +0200

    Fixed incorrect item panel positioning in the crew command interface when the sub is docked to something. Closes #1082

commit 68366a4bf3c73b70288f043199d3ab9b2f5f4d06
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 13:23:38 2019 +0200

    Fixed outdated damage modifiers in security and clown gear (used damage types instead of afflictions), not defining any affliction types for a damage modifier makes it affect all types of damage. Closes #1088

commit 5d3ab5084b8bc5357bc4a53993ad8dfcc44d0412
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 13:04:55 2019 +0200

    Fixed client-side nullref exception if the round ends while the health window is open. Closes #1090

commit 8249d789a60dfe4bcdd1705d26d6ca36ed407058
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Thu Feb 7 12:48:34 2019 +0200

    The dedicated server doesn't initialize a Steam client (not required to use any of the Steam server functionality). Fixes players being unable to log in as a client when they're hosting a dedicated server on another machine. TODO: SteamCMD support

commit 55fb0bb1ba4bb8385dabbf6e40d4651bf86294a9
Author: ezjamsen <ezjames.fi@gmail.com>
Date:   Thu Feb 7 12:31:46 2019 +0200

    Added linked hulls

commit 937d50dca50d8c889a7c11b55765c208d2d16b67
Merge: 8109ae1a3 57731761f
Author: EdusFF <pitkanen.eetu@gmail.com>
Date:   Thu Feb 7 12:16:43 2019 +0200

    Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev

commit 8109ae1a3377910ff9bf066ccac582d879dfb0a4
Author: EdusFF <pitkanen.eetu@gmail.com>
Date:   Thu Feb 7 12:16:37 2019 +0200

    Fixed: AI not reloading coilgun if an empty box of ammunition is inserted.

commit 57731761f64bb33a4f4e7baa38367cfb7cf1f873
Author: itchyOwl <lauri.harkanen@gmail.com>
Date:   Thu Feb 7 12:10:59 2019 +0200

    Refactor character head customization logic and store the data in a dedicated class. In the net lobby, generate new head when the user presses the right arrow button. Pressing the left arrow will restore the previous head. When the user presses the right arrow after the left arrow, the first head is restored again. So it's effectively (and technically) undo/redo logic.

commit 37577931e2706ce432cee2d48cd55990bc2bab4a
Author: itchyOwl <lauri.harkanen@gmail.com>
Date:   Thu Feb 7 12:04:49 2019 +0200

    Add properties for getting the count of the undo and redo stacks.

commit f226beb05a55749ac961e3a33ac594fdf903fc3b
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Wed Feb 6 21:15:56 2019 +0200

    Fixes to hull linking & displaying them as one hull on the minimap:
    - Links between hulls are now saved.
    - Simplified grouping logic (just store a list of linked hulls in hulldata).
    - Fixed water/oxygen calculations (use the average of the values instead of their sum).
    TODO: DRY (there's now duplicate linking logic in Item and Hull), merge the hull sprites on the minimap, maybe automatize the linking?

commit 5dfea1fbb24c5bd91605caf65baaac9aca9cfbbf
Merge: 2ad9b5de4 d06a1557f
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Wed Feb 6 20:18:31 2019 +0200

    Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev

commit d06a1557ffb85cd32bbb884fadef60b6d9dd27cf
Author: Alex <olimpickusa6@gmail.com>
Date:   Wed Feb 6 18:26:40 2019 +0200

    Test for connecting hulls task
2019-03-18 21:13:11 +02:00

751 lines
31 KiB
C#

using Barotrauma.Extensions;
using Barotrauma.Networking;
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
namespace Barotrauma
{
class ServerListScreen : Screen
{
//how often the client is allowed to refresh servers
private TimeSpan AllowedRefreshInterval = new TimeSpan(0, 0, 3);
private GUIFrame menu;
private GUIListBox serverList;
private GUIButton joinButton;
private GUITextBox clientNameBox, ipBox;
private bool masterServerResponded;
private IRestResponse masterServerResponse;
private float[] columnRelativeWidth;
//filters
private GUITextBox searchBox;
private GUITickBox filterPassword;
private GUITickBox filterIncompatible;
private GUITickBox filterFull;
private GUITickBox filterEmpty;
//a timer for
private DateTime refreshDisableTimer;
private bool waitingForRefresh;
public ServerListScreen()
{
int width = Math.Min(GameMain.GraphicsWidth - 160, 1000);
int height = Math.Min(GameMain.GraphicsHeight - 160, 700);
Rectangle panelRect = new Rectangle(0, 0, width, height);
menu = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, Anchor.Center));
new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.133f), menu.RectTransform, Anchor.TopCenter),
TextManager.Get("JoinServer"), textAlignment: Alignment.Left, font: GUI.LargeFont);
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), menu.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.03f) }, style: null);
//-------------------------------------------------------------------------------------
//left column
//-------------------------------------------------------------------------------------
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.25f, 0.92f), paddedFrame.RectTransform, Anchor.TopLeft));
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), leftColumn.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("YourName"));
clientNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.045f), leftColumn.RectTransform), "")
{
Text = GameMain.Config.DefaultPlayerName
};
clientNameBox.OnTextChanged += RefreshJoinButtonState;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("ServerIP"));
// TODO: Show IP on server info window
ipBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.045f), leftColumn.RectTransform), "");
ipBox.OnTextChanged += RefreshJoinButtonState;
ipBox.OnSelected += (sender, key) =>
{
if (sender.UserData is ServerInfo)
{
sender.Text = "";
sender.UserData = null;
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.45f), leftColumn.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterServers"));
searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), "");
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), leftColumn.RectTransform), style: null);
searchBox.OnTextChanged += (txtBox, txt) => { FilterServers(); return true; };
filterPassword = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterPassword"));
filterPassword.OnSelected += (tickBox) => { FilterServers(); return true; };
filterIncompatible = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterIncompatibleServers"));
filterIncompatible.OnSelected += (tickBox) => { FilterServers(); return true; };
filterFull = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterFullServers"));
filterFull.OnSelected += (tickBox) => { FilterServers(); return true; };
filterEmpty = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("FilterEmptyServers"));
filterEmpty.OnSelected += (tickBox) => { FilterServers(); return true; };
//-------------------------------------------------------------------------------------
//right column
//-------------------------------------------------------------------------------------
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - leftColumn.RectTransform.RelativeSize.X - 0.017f, 0.97f),
paddedFrame.RectTransform, Anchor.TopRight))
{
RelativeSpacing = 0.02f,
Stretch = true
};
serverList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.85f), rightColumn.RectTransform, Anchor.Center))
{
OnSelected = SelectServer
};
columnRelativeWidth = new float[] { 0.04f, 0.02f, 0.044f, 0.77f, 0.02f, 0.075f, 0.06f };
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.075f), rightColumn.RectTransform), style: null);
GUIButton button = new GUIButton(new RectTransform(new Vector2(0.25f, 0.9f), buttonContainer.RectTransform, Anchor.TopLeft),
TextManager.Get("Back"), style: "GUIButtonLarge")
{
OnClicked = GameMain.MainMenuScreen.SelectTab
};
var refreshButton = new GUIButton(new RectTransform(new Vector2(buttonContainer.Rect.Height / (float)buttonContainer.Rect.Width, 0.9f), buttonContainer.RectTransform, Anchor.Center),
"", style: "GUIButtonRefresh") {
ToolTip = TextManager.Get("ServerListRefresh"),
OnClicked = RefreshServers
};
joinButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.9f), buttonContainer.RectTransform, Anchor.TopRight),
TextManager.Get("ServerListJoin"), style: "GUIButtonLarge")
{
OnClicked = JoinServer,
Enabled = false
};
//--------------------------------------------------------
button.SelectedColor = button.Color;
refreshDisableTimer = DateTime.Now;
}
public override void Select()
{
base.Select();
RefreshServers(null, null);
}
private void FilterServers()
{
serverList.Content.RemoveChild(serverList.Content.FindChild("noresults"));
foreach (GUIComponent child in serverList.Content.Children)
{
if (!(child.UserData is ServerInfo)) continue;
ServerInfo serverInfo = (ServerInfo)child.UserData;
bool incompatible =
(!serverInfo.ContentPackageHashes.Any() && serverInfo.ContentPackagesMatch(GameMain.Config.SelectedContentPackages)) ||
(!string.IsNullOrEmpty(serverInfo.GameVersion) && serverInfo.GameVersion != GameMain.Version.ToString());
child.Visible =
serverInfo.ServerName.ToLowerInvariant().Contains(searchBox.Text.ToLowerInvariant()) &&
(!filterPassword.Selected || !serverInfo.HasPassword) &&
(!filterIncompatible.Selected || !incompatible) &&
(!filterFull.Selected || serverInfo.PlayerCount < serverInfo.MaxPlayers) &&
(!filterEmpty.Selected || serverInfo.PlayerCount > 0);
}
if (serverList.Content.Children.All(c => !c.Visible))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("NoMatchingServers"))
{
UserData = "noresults"
};
}
}
private bool RefreshJoinButtonState(GUIComponent component, object obj)
{
if (obj == null || waitingForRefresh) return false;
if (!string.IsNullOrWhiteSpace(clientNameBox.Text) && !string.IsNullOrWhiteSpace(ipBox.Text))
{
joinButton.Enabled = true;
}
else
{
joinButton.Enabled = false;
}
return true;
}
private bool SelectServer(GUIComponent component, object obj)
{
if (obj == null || waitingForRefresh) return false;
if (!string.IsNullOrWhiteSpace(clientNameBox.Text))
{
joinButton.Enabled = true;
}
else
{
clientNameBox.Flash();
joinButton.Enabled = false;
}
ServerInfo serverInfo;
try
{
serverInfo = (ServerInfo)obj;
ipBox.UserData = serverInfo;
ipBox.Text = serverInfo.ServerName;
}
catch (InvalidCastException)
{
return false;
}
return true;
}
private bool RefreshServers(GUIButton button, object obj)
{
if (waitingForRefresh) return false;
serverList.ClearChildren();
ipBox.Text = null;
joinButton.Enabled = false;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("RefreshingServerList"));
CoroutineManager.StartCoroutine(WaitForRefresh());
return true;
}
private IEnumerable<object> WaitForRefresh()
{
waitingForRefresh = true;
if (refreshDisableTimer > DateTime.Now)
{
yield return new WaitForSeconds((float)(refreshDisableTimer - DateTime.Now).TotalSeconds);
}
if (GameMain.Config.UseSteamMatchmaking)
{
serverList.ClearChildren();
if (!SteamManager.GetServers(AddToServerList, UpdateServerInfo, ServerQueryFinished))
{
serverList.ClearChildren();
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("ServerListNoSteamConnection"));
}
}
else
{
CoroutineManager.StartCoroutine(SendMasterServerRequest());
}
waitingForRefresh = false;
refreshDisableTimer = DateTime.Now + AllowedRefreshInterval;
yield return CoroutineStatus.Success;
}
private void UpdateServerList(string masterServerData)
{
serverList.ClearChildren();
if (masterServerData.Substring(0, 5).ToLowerInvariant() == "error")
{
DebugConsole.ThrowError("Error while connecting to master server (" + masterServerData + ")!");
return;
}
string[] lines = masterServerData.Split('\n');
List<ServerInfo> serverInfos = new List<ServerInfo>();
for (int i = 0; i < lines.Length; i++)
{
string[] arguments = lines[i].Split('|');
if (arguments.Length < 3) continue;
string ip = arguments[0];
string port = arguments[1];
string serverName = arguments[2];
bool gameStarted = arguments.Length > 3 && arguments[3] == "1";
string currPlayersStr = arguments.Length > 4 ? arguments[4] : "";
string maxPlayersStr = arguments.Length > 5 ? arguments[5] : "";
bool hasPassWord = arguments.Length > 6 && arguments[6] == "1";
string gameVersion = arguments.Length > 7 ? arguments[7] : "";
string contentPackageNames = arguments.Length > 8 ? arguments[8] : "";
string contentPackageHashes = arguments.Length > 9 ? arguments[9] : "";
int.TryParse(currPlayersStr, out int playerCount);
int.TryParse(maxPlayersStr, out int maxPlayers);
var serverInfo = new ServerInfo()
{
IP = ip,
Port = port,
ServerName = serverName,
GameStarted = gameStarted,
PlayerCount = playerCount,
MaxPlayers = maxPlayers,
HasPassword = hasPassWord,
GameVersion = gameVersion
};
foreach (string contentPackageName in contentPackageNames.Split(','))
{
if (string.IsNullOrEmpty(contentPackageName)) continue;
serverInfo.ContentPackageNames.Add(contentPackageName);
}
foreach (string contentPackageHash in contentPackageHashes.Split(','))
{
if (string.IsNullOrEmpty(contentPackageHash)) continue;
serverInfo.ContentPackageHashes.Add(contentPackageHash);
}
serverInfos.Add(serverInfo);
}
serverList.Content.ClearChildren();
if (serverInfos.Count() == 0)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("NoServers"));
return;
}
foreach (ServerInfo serverInfo in serverInfos)
{
AddToServerList(serverInfo);
}
}
private void AddToServerList(ServerInfo serverInfo)
{
var serverFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), serverList.Content.RectTransform) { MinSize = new Point(0, 20) },
style: "InnerFrame", color: Color.White * 0.5f)
{
UserData = serverInfo
};
var serverContent = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 1.0f), serverFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
RelativeSpacing = 0.02f
};
UpdateServerInfo(serverInfo);
}
private void UpdateServerInfo(ServerInfo serverInfo)
{
var serverFrame = serverList.Content.FindChild(serverInfo);
if (serverFrame == null) return;
var serverContent = serverFrame.Children.First();
serverContent.ClearChildren();
var compatibleBox = new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[0], 0.9f), serverContent.RectTransform, Anchor.Center), label: "")
{
Enabled = false,
Selected =
serverInfo.GameVersion == GameMain.Version.ToString() &&
serverInfo.ContentPackagesMatch(GameMain.SelectedPackages),
UserData = "compatible"
};
var passwordBox = new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[1], 0.5f), serverContent.RectTransform, Anchor.Center), label: "", style: "GUIServerListPasswordTickBox")
{
ToolTip = TextManager.Get((serverInfo.HasPassword) ? "ServerListHasPassword" : "FilterPassword"),
Selected = serverInfo.HasPassword,
Enabled = false,
UserData = "password"
};
new GUIButton(new RectTransform(new Vector2(columnRelativeWidth[2], 0.8f), serverContent.RectTransform, Anchor.Center), style: "GUIButtonServerListInfo") {
ToolTip = TextManager.Get("ServerListInfo"),
OnClicked = (btn, obj) => {
SelectServer(null, serverInfo);
var msgBox = new GUIMessageBox("", "", new string[] { TextManager.Get("Cancel"), TextManager.Get("ServerListJoin") }, 550, 400);
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += JoinServer;
msgBox.Buttons[1].OnClicked += msgBox.Close;
serverInfo.CreatePreviewWindow(msgBox);
return true;
}
};
var serverName = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[3], 1.0f), serverContent.RectTransform), serverInfo.ServerName, style: "GUIServerListTextBox");
var gameStartedBox = new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[4], 0.4f), serverContent.RectTransform, Anchor.Center),
label: "", style: "GUIServerListRoundStartedTickBox") {
ToolTip = TextManager.Get((serverInfo.GameStarted) ? "ServerListRoundStarted" : "ServerListRoundNotStarted"),
Selected = serverInfo.GameStarted,
Enabled = false
};
var serverPlayers = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[5], 1.0f), serverContent.RectTransform),
serverInfo.PlayerCount + "/" + serverInfo.MaxPlayers, style: "GUIServerListTextBox", textAlignment: Alignment.Right)
{
ToolTip = TextManager.Get("ServerListPlayers")
};
var serverPingText = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[6], 1.0f), serverContent.RectTransform), "?",
style: "GUIServerListTextBox", textColor: Color.White * 0.5f, textAlignment: Alignment.Right)
{
ToolTip = TextManager.Get("ServerListPing")
};
if (serverInfo.PingChecked)
{
serverPingText.Text = serverInfo.Ping > -1 ? serverInfo.Ping.ToString() : "?";
}
else if (!string.IsNullOrEmpty(serverInfo.IP))
{
try
{
GetServerPing(serverInfo, serverPingText);
}
catch (NullReferenceException ex)
{
DebugConsole.ThrowError("Ping is null", ex);
}
}
if (GameMain.Config.UseSteamMatchmaking && serverInfo.RespondedToSteamQuery.HasValue && serverInfo.RespondedToSteamQuery.Value == false)
{
string toolTip = TextManager.Get("ServerListNoSteamQueryResponse");
compatibleBox.Selected = false;
serverContent.Children.ForEach(c => c.ToolTip = toolTip);
serverName.TextColor *= 0.8f;
serverPlayers.TextColor *= 0.8f;
}
else if (string.IsNullOrEmpty(serverInfo.GameVersion) || !serverInfo.ContentPackageHashes.Any())
{
compatibleBox.Selected = false;
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.8f), compatibleBox.Box.RectTransform, Anchor.Center), " ? ", Color.Yellow * 0.85f, textAlignment: Alignment.Center)
{
ToolTip = TextManager.Get(string.IsNullOrEmpty(serverInfo.GameVersion) ?
"ServerListUnknownVersion" :
"ServerListUnknownContentPackage")
};
}
else if (!compatibleBox.Selected)
{
string toolTip = "";
if (serverInfo.GameVersion != GameMain.Version.ToString())
toolTip = TextManager.Get("ServerListIncompatibleVersion").Replace("[version]", serverInfo.GameVersion);
for (int i = 0; i < serverInfo.ContentPackageNames.Count; i++)
{
if (!GameMain.SelectedPackages.Any(cp => cp.MD5hash.Hash == serverInfo.ContentPackageHashes[i]))
{
if (toolTip != "") toolTip += "\n";
toolTip += TextManager.Get("ServerListIncompatibleContentPackage")
.Replace("[contentpackage]", serverInfo.ContentPackageNames[i])
.Replace("[hash]", Md5Hash.GetShortHash(serverInfo.ContentPackageHashes[i]));
}
}
serverContent.Children.ForEach(c => c.ToolTip = toolTip);
serverName.TextColor *= 0.5f;
serverPlayers.TextColor *= 0.5f;
}
FilterServers();
}
private void ServerQueryFinished()
{
if (serverList.Content.Children.All(c => !c.Visible))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverList.Content.RectTransform),
TextManager.Get("NoMatchingServers"))
{
UserData = "noresults"
};
}
}
private IEnumerable<object> SendMasterServerRequest()
{
RestClient client = null;
try
{
client = new RestClient(NetConfig.MasterServerUrl);
}
catch (Exception e)
{
DebugConsole.ThrowError("Error while connecting to master server", e);
}
if (client == null) yield return CoroutineStatus.Success;
var request = new RestRequest("masterserver2.php", Method.GET);
request.AddParameter("gamename", "barotrauma");
request.AddParameter("action", "listservers");
// execute the request
masterServerResponded = false;
var restRequestHandle = client.ExecuteAsync(request, response => MasterServerCallBack(response));
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 8);
while (!masterServerResponded)
{
if (DateTime.Now > timeOut)
{
serverList.ClearChildren();
restRequestHandle.Abort();
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"), TextManager.Get("MasterServerTimeOutError"));
yield return CoroutineStatus.Success;
}
yield return CoroutineStatus.Running;
}
if (masterServerResponse.ErrorException != null)
{
serverList.ClearChildren();
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"), TextManager.Get("MasterServerErrorException").Replace("[error]", masterServerResponse.ErrorException.ToString()));
}
else if (masterServerResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
serverList.ClearChildren();
switch (masterServerResponse.StatusCode)
{
case System.Net.HttpStatusCode.NotFound:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
TextManager.Get("MasterServerError404")
.Replace("[masterserverurl]", NetConfig.MasterServerUrl)
.Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
.Replace("[statusdescription]", masterServerResponse.StatusDescription));
break;
case System.Net.HttpStatusCode.ServiceUnavailable:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
TextManager.Get("MasterServerErrorUnavailable")
.Replace("[masterserverurl]", NetConfig.MasterServerUrl)
.Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
.Replace("[statusdescription]", masterServerResponse.StatusDescription));
break;
default:
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
TextManager.Get("MasterServerError404")
.Replace("[masterserverurl]", NetConfig.MasterServerUrl)
.Replace("[statuscode]", masterServerResponse.StatusCode.ToString())
.Replace("[statusdescription]", masterServerResponse.StatusDescription));
break;
}
}
else
{
UpdateServerList(masterServerResponse.Content);
}
yield return CoroutineStatus.Success;
}
private void MasterServerCallBack(IRestResponse response)
{
masterServerResponse = response;
masterServerResponded = true;
}
private bool JoinServer(GUIButton button, object obj)
{
if (string.IsNullOrWhiteSpace(clientNameBox.Text))
{
clientNameBox.Flash();
joinButton.Enabled = false;
return false;
}
GameMain.Config.DefaultPlayerName = clientNameBox.Text;
GameMain.Config.Save();
string ip = null;
if (ipBox.UserData is ServerInfo serverInfo)
{
ip = serverInfo.IP + ":" + serverInfo.Port;
}
else if (!string.IsNullOrWhiteSpace(ipBox.Text))
{
ip = ipBox.Text;
}
if (string.IsNullOrWhiteSpace(ip))
{
ipBox.Flash();
joinButton.Enabled = false;
return false;
}
CoroutineManager.StartCoroutine(ConnectToServer(ip));
return true;
}
private IEnumerable<object> ConnectToServer(string ip)
{
try
{
GameMain.NetworkMember = new GameClient(clientNameBox.Text);
GameMain.Client.ConnectToServer(ip);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to start the client", e);
}
yield return CoroutineStatus.Success;
}
public void GetServerPing(ServerInfo serverInfo, GUITextBlock serverPingText)
{
serverInfo.PingChecked = false;
serverInfo.Ping = -1;
var pingThread = new Thread(() => { PingServer(serverInfo, 1000); })
{
IsBackground = true
};
pingThread.Start();
CoroutineManager.StartCoroutine(UpdateServerPingText(serverInfo, serverPingText, 1000));
}
private IEnumerable<object> UpdateServerPingText(ServerInfo serverInfo, GUITextBlock serverPingText, int timeOut)
{
DateTime timeOutTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: timeOut);
while (DateTime.Now < timeOutTime)
{
if (serverInfo.PingChecked)
{
if (serverInfo.Ping != -1)
{
if (serverInfo.Ping < 50)
{
serverPingText.TextColor = Color.Green * 1.75f;
}
else if (serverInfo.Ping < 150)
{
serverPingText.TextColor = Color.Yellow * 0.85f;
}
else
{
serverPingText.TextColor = Color.Red * 0.75f;
}
}
serverPingText.Text = serverInfo.Ping > -1 ? serverInfo.Ping.ToString() : "?";
yield return CoroutineStatus.Success;
}
yield return CoroutineStatus.Running;
}
yield return CoroutineStatus.Success;
}
public void PingServer(ServerInfo serverInfo, int timeOut)
{
if (serverInfo?.IP == null)
{
serverInfo.PingChecked = true;
serverInfo.Ping = -1;
return;
}
long rtt = -1;
IPAddress address = IPAddress.Parse(serverInfo.IP);
if (address != null)
{
//don't attempt to ping if the address is IPv6 and it's not supported
if (address.AddressFamily != AddressFamily.InterNetworkV6 || Socket.OSSupportsIPv6)
{
Ping ping = new Ping();
byte[] buffer = new byte[32];
try
{
PingReply pingReply = ping.Send(address, timeOut, buffer, new PingOptions(128, true));
if (pingReply != null)
{
switch (pingReply.Status)
{
case IPStatus.Success:
rtt = pingReply.RoundtripTime;
break;
default:
rtt = -1;
break;
}
}
}
catch (PingException ex)
{
string errorMsg = "Failed to ping a server (" + serverInfo.ServerName + ", " + serverInfo.IP + ") - " + (ex?.InnerException?.Message ?? ex.Message);
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + serverInfo.IP, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
#if DEBUG
DebugConsole.NewMessage(errorMsg, Color.Red);
#endif
}
}
}
serverInfo.PingChecked = true;
serverInfo.Ping = (int)rtt;
}
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
graphics.Clear(Color.CornflowerBlue);
GameMain.TitleScreen.DrawLoadingText = false;
GameMain.TitleScreen.Draw(spriteBatch, graphics, (float)deltaTime);
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable);
GUI.Draw(Cam, spriteBatch);
spriteBatch.End();
}
public override void AddToGUIUpdateList()
{
menu.AddToGUIUpdateList();
}
}
}