public GameMain(string[] args) { Content.RootDirectory = "Content"; #if DEBUG && WINDOWS GraphicsAdapter.UseDebugLayers = true; #endif GraphicsDeviceManager = new GraphicsDeviceManager(this) { IsFullScreen = false, GraphicsProfile = GfxProfile }; GraphicsDeviceManager.ApplyChanges(); Window.Title = "Barotrauma"; Instance = this; if (!Directory.Exists(Content.RootDirectory)) { throw new Exception("Content folder not found. If you are trying to compile the game from the source code and own a legal copy of the game, you can copy the Content folder from the game's files to BarotraumaShared/Content."); } Config = new GameSettings(); Md5Hash.LoadCache(); ConsoleArguments = args; ConnectName = null; ConnectEndpoint = null; ConnectLobby = 0; try { ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby); } catch (IndexOutOfRangeException e) { DebugConsole.ThrowError($"Failed to parse console arguments ({string.Join(' ', ConsoleArguments)})", e); ConnectName = null; ConnectEndpoint = null; ConnectLobby = 0; } GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window); PerformanceCounter = new PerformanceCounter(); IsFixedTimeStep = false; GameMain.ResetFrameTime(); fixedTime = new GameTime(); World = new World(new Vector2(0, -9.82f)); FarseerPhysics.Settings.AllowSleep = true; FarseerPhysics.Settings.ContinuousPhysics = false; FarseerPhysics.Settings.VelocityIterations = 1; FarseerPhysics.Settings.PositionIterations = 1; MainThread = Thread.CurrentThread; }
public static void Init() { #if DEBUG try { GameAnalytics.SetEnabledInfoLog(true); } catch (Exception e) { DebugConsole.ThrowError("Initializing GameAnalytics failed. Disabling user statistics...", e); GameSettings.SendUserStatistics = false; return; } #endif string exePath = Assembly.GetEntryAssembly().Location; string exeName = null; Md5Hash exeHash = null; exeName = Path.GetFileNameWithoutExtension(exePath).Replace(":", ""); var md5 = MD5.Create(); try { using (var stream = File.OpenRead(exePath)) { exeHash = new Md5Hash(stream); } } catch (Exception e) { DebugConsole.ThrowError("Error while calculating MD5 hash for the executable \"" + exePath + "\"", e); } try { GameAnalytics.ConfigureBuild(GameMain.Version.ToString() + (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":" + ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash)); GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor"); GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7"); GameAnalytics.AddDesignEvent("Executable:" + (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":" + ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash)); } catch (Exception e) { DebugConsole.ThrowError("Initializing GameAnalytics failed. Disabling user statistics...", e); GameSettings.SendUserStatistics = false; return; } if (GameMain.Config?.SelectedContentPackages.Count > 0) { StringBuilder sb = new StringBuilder("ContentPackage: "); int i = 0; foreach (ContentPackage cp in GameMain.Config.SelectedContentPackages) { string trimmedName = cp.Name.Replace(":", "").Replace(" ", ""); sb.Append(trimmedName.Substring(0, Math.Min(32, trimmedName.Length))); if (i < GameMain.Config.SelectedContentPackages.Count - 1) { sb.Append(" "); } } GameAnalytics.AddDesignEvent(sb.ToString()); } }
static void CrashDump(GameMain game, string filePath, Exception exception) { int existingFiles = 0; string originalFilePath = filePath; while (File.Exists(filePath)) { existingFiles++; filePath = Path.GetFileNameWithoutExtension(originalFilePath) + " (" + (existingFiles + 1) + ")" + Path.GetExtension(originalFilePath); } DebugConsole.DequeueMessages(); string exePath = System.Reflection.Assembly.GetEntryAssembly().Location; var md5 = System.Security.Cryptography.MD5.Create(); Md5Hash exeHash = null; try { using (var stream = File.OpenRead(exePath)) { exeHash = new Md5Hash(stream); } } catch { //gotta catch them all, we don't want to throw an exception while writing a crash report } StreamWriter sw = new StreamWriter(filePath); StringBuilder sb = new StringBuilder(); sb.AppendLine("Barotrauma Client crash report (generated on " + DateTime.Now + ")"); sb.AppendLine("\n"); sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! "); sb.AppendLine("\n"); if (exeHash?.Hash != null) { sb.AppendLine(exeHash.Hash); } sb.AppendLine("\n"); #if DEBUG sb.AppendLine("Game version " + GameMain.Version + " (debug build)"); #else sb.AppendLine("Game version " + GameMain.Version); #endif if (GameMain.Config != null) { sb.AppendLine("Graphics mode: " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight + " (" + GameMain.Config.WindowMode.ToString() + ")"); } if (GameMain.SelectedPackages != null) { sb.AppendLine("Selected content packages: " + (!GameMain.SelectedPackages.Any() ? "None" : string.Join(", ", GameMain.SelectedPackages.Select(c => c.Name)))); } sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed)); sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash + ")")); sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString())); if (SteamManager.IsInitialized) { sb.AppendLine("SteamManager initialized"); } if (GameMain.Client != null) { sb.AppendLine("Client (" + (GameMain.Client.GameStarted ? "Round had started)" : "Round hadn't been started)")); } sb.AppendLine("\n"); sb.AppendLine("System info:"); sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86")); if (game == null) { sb.AppendLine(" Game not initialized"); } else { if (game.GraphicsDevice == null) { sb.AppendLine(" Graphics device not set"); } else { if (game.GraphicsDevice.Adapter == null) { sb.AppendLine(" Graphics adapter not set"); } else { sb.AppendLine(" GPU name: " + game.GraphicsDevice.Adapter.Description); sb.AppendLine(" Display mode: " + game.GraphicsDevice.Adapter.CurrentDisplayMode); } sb.AppendLine(" GPU status: " + game.GraphicsDevice.GraphicsDeviceStatus); } } sb.AppendLine("\n"); sb.AppendLine("Exception: " + exception.Message); if (exception.TargetSite != null) { sb.AppendLine("Target site: " + exception.TargetSite.ToString()); } sb.AppendLine("Stack trace: "); sb.AppendLine(exception.StackTrace); sb.AppendLine("\n"); if (exception.InnerException != null) { sb.AppendLine("InnerException: " + exception.InnerException.Message); if (exception.InnerException.TargetSite != null) { sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString()); } sb.AppendLine("Stack trace: "); sb.AppendLine(exception.InnerException.StackTrace); } sb.AppendLine("Last debug messages:"); for (int i = DebugConsole.Messages.Count - 1; i >= 0; i--) { sb.AppendLine("[" + DebugConsole.Messages[i].Time + "] " + DebugConsole.Messages[i].Text); } string crashReport = sb.ToString(); sw.WriteLine(crashReport); sw.Close(); if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); } if (GameSettings.SendUserStatistics) { CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game and sent to the developers.", filePath); GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport); GameAnalytics.OnQuit(); } else { CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game. The error was not sent to the developers because user statistics have been disabled, but" + " if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/", filePath); } }
static void CrashDump(GameMain game, string filePath, Exception exception) { int existingFiles = 0; string originalFilePath = filePath; while (File.Exists(filePath)) { existingFiles++; filePath = Path.GetFileNameWithoutExtension(originalFilePath) + " (" + (existingFiles + 1) + ")" + Path.GetExtension(originalFilePath); } DebugConsole.DequeueMessages(); Md5Hash exeHash = null; try { string exePath = System.Reflection.Assembly.GetEntryAssembly().Location; var md5 = System.Security.Cryptography.MD5.Create(); byte[] exeBytes = File.ReadAllBytes(exePath); exeHash = new Md5Hash(exeBytes); } catch { //do nothing, generate the rest of the crash report } StringBuilder sb = new StringBuilder(); sb.AppendLine("Barotrauma Client crash report (generated on " + DateTime.Now + ")"); sb.AppendLine("\n"); sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! "); sb.AppendLine("\n"); try { if (exception is GameMain.LoadingException) { //exception occurred in loading screen: //assume content packages are the culprit and reset them XDocument doc = XMLExtensions.TryLoadXml(GameSettings.PlayerSavePath); XDocument baseDoc = XMLExtensions.TryLoadXml(GameSettings.SavePath); if (doc != null && baseDoc != null) { XElement newElement = new XElement(doc.Root.Name); newElement.Add(doc.Root.Attributes()); newElement.Add(doc.Root.Elements().Where(e => !e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase))); newElement.Add(baseDoc.Root.Elements().Where(e => e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase))); XDocument newDoc = new XDocument(newElement); newDoc.Save(GameSettings.PlayerSavePath); sb.AppendLine("To prevent further startup errors, installed mods will be disabled the next time you launch the game."); sb.AppendLine("\n"); } } } catch { //welp i guess we couldn't reset the config! } if (exeHash?.Hash != null) { sb.AppendLine(exeHash.Hash); } sb.AppendLine("\n"); sb.AppendLine("Game version " + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")"); if (GameMain.Config != null) { sb.AppendLine("Graphics mode: " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight + " (" + GameMain.Config.WindowMode.ToString() + ")"); sb.AppendLine("VSync " + (GameMain.Config.VSyncEnabled ? "ON" : "OFF")); sb.AppendLine("Language: " + (GameMain.Config.Language ?? "none")); } if (GameMain.Config.AllEnabledPackages != null) { sb.AppendLine("Selected content packages: " + (!GameMain.Config.AllEnabledPackages.Any() ? "None" : string.Join(", ", GameMain.Config.AllEnabledPackages.Select(c => c.Name)))); } sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed)); sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")")); sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString())); if (SteamManager.IsInitialized) { sb.AppendLine("SteamManager initialized"); } if (GameMain.Client != null) { sb.AppendLine("Client (" + (GameMain.Client.GameStarted ? "Round had started)" : "Round hadn't been started)")); } sb.AppendLine("\n"); sb.AppendLine("System info:"); sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86")); if (game == null) { sb.AppendLine(" Game not initialized"); } else { if (game.GraphicsDevice == null) { sb.AppendLine(" Graphics device not set"); } else { if (game.GraphicsDevice.Adapter == null) { sb.AppendLine(" Graphics adapter not set"); } else { sb.AppendLine(" GPU name: " + game.GraphicsDevice.Adapter.Description); sb.AppendLine(" Display mode: " + game.GraphicsDevice.Adapter.CurrentDisplayMode); } sb.AppendLine(" GPU status: " + game.GraphicsDevice.GraphicsDeviceStatus); } } sb.AppendLine("\n"); sb.AppendLine("Exception: " + exception.Message + " (" + exception.GetType().ToString() + ")"); #if WINDOWS if (exception is SharpDXException sharpDxException && ((uint)sharpDxException.HResult) == 0x887A0005) { var dxDevice = (SharpDX.Direct3D11.Device)game.GraphicsDevice.Handle; sb.AppendLine("Device removed reason: " + dxDevice.DeviceRemovedReason.ToString()); } #endif if (exception.TargetSite != null) { sb.AppendLine("Target site: " + exception.TargetSite.ToString()); } sb.AppendLine("Stack trace: "); sb.AppendLine(exception.StackTrace.CleanupStackTrace()); sb.AppendLine("\n"); if (exception.InnerException != null) { sb.AppendLine("InnerException: " + exception.InnerException.Message); if (exception.InnerException.TargetSite != null) { sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString()); } sb.AppendLine("Stack trace: "); sb.AppendLine(exception.InnerException.StackTrace.CleanupStackTrace()); } sb.AppendLine("Last debug messages:"); for (int i = DebugConsole.Messages.Count - 1; i >= 0; i--) { sb.AppendLine("[" + DebugConsole.Messages[i].Time + "] " + DebugConsole.Messages[i].Text); } string crashReport = sb.ToString(); File.WriteAllText(filePath, crashReport); if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); } if (GameSettings.SendUserStatistics) { CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game and sent to the developers.", filePath); GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport); GameAnalytics.OnQuit(); } else { CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game. The error was not sent to the developers because user statistics have been disabled, but" + " if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/", filePath); } }
private void UpdateServerInfo(ServerInfo serverInfo) { var serverFrame = serverList.Content.FindChild(serverInfo); if (serverFrame == null) { return; } var serverContent = serverFrame.Children.First() as GUILayoutGroup; 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" }; var serverName = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[2] * 1.1f, 1.0f), serverContent.RectTransform), serverInfo.ServerName, style: "GUIServerListTextBox"); new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[3], 0.9f), serverContent.RectTransform, Anchor.Center), label: "") { ToolTip = TextManager.Get((serverInfo.GameStarted) ? "ServerListRoundStarted" : "ServerListRoundNotStarted"), Selected = serverInfo.GameStarted, Enabled = false }; var serverPlayers = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[4], 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[5], 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() : "?"; serverPingText.TextColor = GetPingTextColor(serverInfo.Ping); } 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.GetWithVariable("ServerListIncompatibleVersion", "[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.GetWithVariables("ServerListIncompatibleContentPackage", new string[2] { "[contentpackage]", "[hash]" }, new string[2] { serverInfo.ContentPackageNames[i], Md5Hash.GetShortHash(serverInfo.ContentPackageHashes[i]) }); } } serverContent.Children.ForEach(c => c.ToolTip = toolTip); serverName.TextColor *= 0.5f; serverPlayers.TextColor *= 0.5f; } serverContent.Recalculate(); SortList(sortedBy, toggle: false); FilterServers(); }
//constructors & generation ---------------------------------------------------- public Submarine(string filePath, string hash = "", bool tryLoad = true) : base(null) { this.filePath = filePath; try { name = System.IO.Path.GetFileNameWithoutExtension(filePath); } catch (Exception e) { DebugConsole.ThrowError("Error loading submarine " + filePath + "!", e); } if (hash != "") { this.hash = new Md5Hash(hash); } if (tryLoad) { XDocument doc = OpenFile(filePath); if (doc != null && doc.Root != null) { Description = doc.Root.GetAttributeString("description", ""); Enum.TryParse(doc.Root.GetAttributeString("tags", ""), out tags); Dimensions = doc.Root.GetAttributeVector2("dimensions", Vector2.Zero); RecommendedCrewSizeMin = doc.Root.GetAttributeInt("recommendedcrewsizemin", 0); RecommendedCrewSizeMax = doc.Root.GetAttributeInt("recommendedcrewsizemax", 0); RecommendedCrewExperience = doc.Root.GetAttributeString("recommendedcrewexperience", "Unknown"); string[] contentPackageNames = doc.Root.GetAttributeStringArray("compatiblecontentpackages", new string[0]); foreach (string contentPackageName in contentPackageNames) { CompatibleContentPackages.Add(contentPackageName); } #if CLIENT string previewImageData = doc.Root.GetAttributeString("previewimage", ""); if (!string.IsNullOrEmpty(previewImageData)) { try { using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData))) { PreviewImage = new Sprite(TextureLoader.FromStream(mem), null, null); } } catch (Exception e) { DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e); GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted."); PreviewImage = null; } } #endif } } DockedTo = new List <Submarine>(); ID = ushort.MaxValue; FreeID(); }
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(); }