From 7799e053695b27eb12faae3fed8976e7058e4d35 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 12:59:17 +0300 Subject: [PATCH 01/29] GameAnalyticsManager sends the name and MD5 hash of the currently running exe (can be used to recognize code modifications that use the vanilla content package) --- .../Source/GameAnalyticsManager.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs index c9983f7a5..81374dab6 100644 --- a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs @@ -1,5 +1,9 @@ using GameAnalyticsSDK.Net; using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; namespace Barotrauma { @@ -11,9 +15,31 @@ namespace Barotrauma GameAnalytics.SetEnabledInfoLog(true); #endif GameAnalytics.ConfigureBuild(GameMain.Version.ToString()); + + 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); + } + + GameAnalytics.AddDesignEvent("Executable:" + + (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":" + + ((exeHash == null) ? "Unknown" : exeHash.ShortHash)); + GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor"); GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7"); - + string contentPackageName = GameMain.Config?.SelectedContentPackage?.Name; if (!string.IsNullOrEmpty(contentPackageName)) { From cbb207dbca53ea8b0fdd28722b1a86681c054284 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 12:59:59 +0300 Subject: [PATCH 02/29] Cleanbuild console command resets the user statistics setting --- Barotrauma/BarotraumaClient/Source/DebugConsole.cs | 2 ++ Barotrauma/BarotraumaClient/Source/GameMain.cs | 10 ++++++++-- Barotrauma/BarotraumaShared/Source/GameSettings.cs | 10 +++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index b095508b2..0a3a91434 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -438,6 +438,8 @@ namespace Barotrauma NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green); NewMessage("Fullscreen enabled", Color.Green); + GameSettings.ShowUserStatisticsPrompt = true; + GameSettings.VerboseLogging = false; if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster") diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 73363e61b..5a572c463 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -134,7 +134,7 @@ namespace Barotrauma Config.WasGameUpdated = false; Config.Save("config.xml"); } - + ApplyGraphicsSettings(); Content.RootDirectory = "Content"; @@ -244,12 +244,18 @@ namespace Barotrauma new string[] { "Yes", "No" }); userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) => { + GameSettings.ShowUserStatisticsPrompt = false; GameSettings.SendUserStatistics = true; GameAnalyticsManager.Init(); return true; }; userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close; - userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) => { GameSettings.SendUserStatistics = false; return true; }; + userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) => + { + GameSettings.ShowUserStatisticsPrompt = false; + GameSettings.SendUserStatistics = false; + return true; + }; userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close; } else if (GameSettings.SendUserStatistics) diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index a476f143f..fbc3b2fe8 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -164,7 +164,7 @@ namespace Barotrauma GameMain.Config.Save("config.xml"); } } - public static bool ShowUserStatisticsPrompt { get; private set; } + public static bool ShowUserStatisticsPrompt { get; set; } public GameSettings(string filePath) { @@ -334,8 +334,12 @@ namespace Barotrauma new XAttribute("soundvolume", soundVolume), new XAttribute("verboselogging", VerboseLogging), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), - new XAttribute("enablesplashscreen", EnableSplashScreen), - new XAttribute("senduserstatistics", sendUserStatistics)); + new XAttribute("enablesplashscreen", EnableSplashScreen)); + + if (!ShowUserStatisticsPrompt) + { + doc.Root.Add(new XAttribute("senduserstatistics", sendUserStatistics)); + } if (WasGameUpdated) { From af4d60db1da92668d49d0b1c4c2ba7d1b12bfff1 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 13:05:58 +0300 Subject: [PATCH 03/29] Fixed GameMain.Server.Character not being set to null when the character is removed. Closes #488 --- Barotrauma/BarotraumaClient/Source/Characters/Character.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs index f5feec38b..597bdc902 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs @@ -206,8 +206,8 @@ namespace Barotrauma { GameMain.GameSession.CrewManager.RemoveCharacter(this); } - - if (GameMain.Client != null && GameMain.Client.Character == this) GameMain.Client.Character = null; + + if (GameMain.NetworkMember?.Character == this) GameMain.NetworkMember.Character = null; if (Lights.LightManager.ViewTarget == this) Lights.LightManager.ViewTarget = null; } From 568cf1a02ff415b020bb1f17c3ca14b730d3a146 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 14:23:43 +0300 Subject: [PATCH 04/29] Fixed memory leak caused by submarine preview images, changed Submarine.SavedSubmarines to a property that prevents removing submarines from outside the class without disposing the preview image. Closes #498 --- .../Source/Networking/GameClient.cs | 10 +- .../Source/Networking/Voting.cs | 3 +- .../Source/Screens/CampaignSetupUI.cs | 2 +- .../Source/Screens/NetLobbyScreen.cs | 8 +- .../BarotraumaClient/Source/Sprite/Sprite.cs | 10 +- .../Source/Screens/NetLobbyScreen.cs | 4 +- .../BarotraumaShared/Source/Map/Submarine.cs | 92 ++++++++++++------- .../Networking/FileTransfer/FileSender.cs | 2 +- .../Source/Networking/Voting.cs | 2 +- 9 files changed, 81 insertions(+), 52 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 47c0a4e7a..5e097dffd 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -815,7 +815,7 @@ namespace Barotrauma.Networking string subName = inc.ReadString(); string subHash = inc.ReadString(); - var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == subName && s.MD5Hash.Hash == subHash); + var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash); if (matchingSub != null) { submarines.Add(matchingSub); @@ -1181,8 +1181,12 @@ namespace Barotrauma.Networking case FileTransferType.Submarine: new GUIMessageBox("Download finished", "File \"" + transfer.FileName + "\" was downloaded succesfully."); var newSub = new Submarine(transfer.FilePath); - Submarine.SavedSubmarines.RemoveAll(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash); - Submarine.SavedSubmarines.Add(newSub); + var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList(); + foreach (Submarine existingSub in existingSubs) + { + existingSub.Dispose(); + } + Submarine.AddToSavedSubs(newSub); for (int i = 0; i < 2; i++) { diff --git a/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs b/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs index b0a6294bb..6b41a5dac 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/Voting.cs @@ -2,6 +2,7 @@ using Lidgren.Network; using Microsoft.Xna.Framework; using System.Collections.Generic; +using System.Linq; namespace Barotrauma { @@ -151,7 +152,7 @@ namespace Barotrauma { int votes = inc.ReadByte(); string subName = inc.ReadString(); - Submarine sub = Submarine.SavedSubmarines.Find(sm => sm.Name == subName); + Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(sm => sm.Name == subName); SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index b477aee46..578ee4bf0 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -144,7 +144,7 @@ namespace Barotrauma return true; }; } - if (Submarine.SavedSubmarines.Count > 0) subList.Select(Submarine.SavedSubmarines[0]); + if (Submarine.SavedSubmarines.Any()) subList.Select(Submarine.SavedSubmarines.First()); } public void UpdateLoadMenu() diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 6f5edabac..287edb042 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -782,8 +782,8 @@ namespace Barotrauma CanBeFocused = false }; - var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash); - if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == sub.Name); + var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash); + if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name); if (matchingSub == null) { @@ -1467,8 +1467,8 @@ namespace Barotrauma return false; } - Submarine sub = Submarine.SavedSubmarines.Find(m => m.Name == subName && m.MD5Hash.Hash == md5Hash); - if (sub == null) sub = Submarine.SavedSubmarines.Find(m => m.Name == subName); + Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName && m.MD5Hash.Hash == md5Hash); + if (sub == null) sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName); var matchingListSub = subList.children.Find(c => c.UserData == sub); if (matchingListSub != null) diff --git a/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs index c0e65a76f..d09deb6b0 100644 --- a/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs @@ -254,11 +254,14 @@ namespace Barotrauma partial void DisposeTexture() { //check if another sprite is using the same texture - foreach (Sprite s in list) + if (!string.IsNullOrEmpty(file)) //file can be empty if the sprite is created directly from a Texture2D instance { - if (s.file == file) return; + foreach (Sprite s in list) + { + if (s.file == file) return; + } } - + //if not, free the texture if (texture != null) { @@ -267,6 +270,5 @@ namespace Barotrauma } } } - } diff --git a/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs index 959d85b2c..79fffa92f 100644 --- a/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs @@ -119,7 +119,7 @@ namespace Barotrauma subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus)).ToList(); - if (subs == null || subs.Count()==0) + if (subs == null || subs.Count() == 0) { throw new Exception("No submarines are available."); } @@ -187,7 +187,7 @@ namespace Barotrauma if (GameMain.Server.SubSelectionMode == SelectionMode.Random) { - var nonShuttles = Submarine.SavedSubmarines.FindAll(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)); + var nonShuttles = Submarine.SavedSubmarines.Where(c => !c.HasTag(SubmarineTag.Shuttle) && !c.HasTag(SubmarineTag.HideInMenus)).ToList(); SelectedSub = nonShuttles[Rand.Range(0, nonShuttles.Count)]; } if (GameMain.Server.ModeSelectionMode == SelectionMode.Random) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 63277d538..e5ade2ae9 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -51,8 +51,12 @@ namespace Barotrauma public static bool LockX, LockY; - public static List SavedSubmarines = new List(); - + private static List savedSubmarines = new List(); + public static IEnumerable SavedSubmarines + { + get { return savedSubmarines; } + } + public static readonly Vector2 GridSize = new Vector2(16.0f, 16.0f); public static Submarine[] MainSubs = new Submarine[2]; @@ -214,10 +218,10 @@ namespace Barotrauma return ConvertUnits.ToSimUnits(Position); } } - + public Vector2 Velocity { - get { return subBody==null ? Vector2.Zero : subBody.Velocity; } + get { return subBody == null ? Vector2.Zero : subBody.Velocity; } set { if (subBody == null) return; @@ -244,7 +248,7 @@ namespace Barotrauma public override string ToString() { - return "Barotrauma.Submarine ("+name+")"; + return "Barotrauma.Submarine (" + name + ")"; } public override bool Removed @@ -344,7 +348,7 @@ namespace Barotrauma { if (dockedSub == this) continue; - Vector2 diff = dockedSub.Submarine == this ? dockedSub.WorldPosition : dockedSub.WorldPosition - WorldPosition; + Vector2 diff = dockedSub.Submarine == this ? dockedSub.WorldPosition : dockedSub.WorldPosition - WorldPosition; Rectangle dockedSubBorders = dockedSub.Borders; dockedSubBorders.Y -= dockedSubBorders.Height; @@ -383,15 +387,15 @@ namespace Barotrauma public Vector2 FindSpawnPos(Vector2 spawnPos) { Rectangle dockedBorders = GetDockedBorders(); - + int iterations = 0; bool wallTooClose = false; do { Rectangle worldBorders = new Rectangle( dockedBorders.X + (int)spawnPos.X, - dockedBorders.Y + (int)spawnPos.Y, - dockedBorders.Width, + dockedBorders.Y + (int)spawnPos.Y, + dockedBorders.Width, dockedBorders.Height); wallTooClose = false; @@ -507,8 +511,8 @@ namespace Barotrauma public Rectangle CalculateDimensions(bool onlyHulls = true) { - List entities = onlyHulls ? - Hull.hullList.FindAll(h => h.Submarine == this).Cast().ToList() : + List entities = onlyHulls ? + Hull.hullList.FindAll(h => h.Submarine == this).Cast().ToList() : MapEntity.mapEntityList.FindAll(me => me.Submarine == this); if (entities.Count == 0) return Rectangle.Empty; @@ -557,7 +561,7 @@ namespace Barotrauma } } - public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true) + public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive = true) { if (inclusive) { @@ -584,25 +588,25 @@ namespace Barotrauma { if (fixture == null || (ignoreSensors && fixture.IsSensor) || - fixture.CollisionCategories == Category.None || + fixture.CollisionCategories == Category.None || fixture.CollisionCategories == Physics.CollisionItem) return -1; - - if (collisionCategory != null && + + if (collisionCategory != null && !fixture.CollisionCategories.HasFlag((Category)collisionCategory) && !((Category)collisionCategory).HasFlag(fixture.CollisionCategories)) return -1; - + if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1; - - Structure structure = fixture.Body.UserData as Structure; + + Structure structure = fixture.Body.UserData as Structure; if (structure != null) { if (structure.IsPlatform && collisionCategory != null && !((Category)collisionCategory).HasFlag(Physics.CollisionPlatform)) return -1; - } + } if (fraction < closestFraction) { closestFraction = fraction; - if (fixture.Body!=null) closestBody = fixture.Body; + if (fixture.Body != null) closestBody = fixture.Body; } return fraction; } @@ -669,7 +673,7 @@ namespace Barotrauma get { return flippedX; } } - public void FlipX(List parents=null) + public void FlipX(List parents = null) { if (parents == null) parents = new List(); parents.Add(this); @@ -729,7 +733,7 @@ namespace Barotrauma { if (bodyItems.Contains(item)) { - item.Submarine = this; + item.Submarine = this; if (Position == Vector2.Zero) item.Move(-HiddenSubPosition); } else if (item.Submarine != this) @@ -751,7 +755,7 @@ namespace Barotrauma if (Level.Loaded == null || subBody == null) return; if (WorldPosition.Y < Level.MaxEntityDepth && - subBody.Body.Enabled && + subBody.Body.Enabled && (GameMain.NetworkMember?.RespawnManager == null || this != GameMain.NetworkMember.RespawnManager.RespawnShuttle)) { subBody.Body.ResetDynamics(); @@ -778,26 +782,26 @@ namespace Barotrauma } subBody.Body.LinearVelocity = new Vector2( - LockX ? 0.0f : subBody.Body.LinearVelocity.X, + LockX ? 0.0f : subBody.Body.LinearVelocity.X, LockY ? 0.0f : subBody.Body.LinearVelocity.Y); - - + + subBody.Update(deltaTime); - for (int i = 0; i < 2; i++ ) + for (int i = 0; i < 2; i++) { if (MainSubs[i] == null) continue; if (this != MainSubs[i] && MainSubs[i].DockedTo.Contains(this)) return; } //send updates more frequently if moving fast - networkUpdateTimer -= MathHelper.Clamp(Velocity.Length()*10.0f, 0.1f, 5.0f) * deltaTime; + networkUpdateTimer -= MathHelper.Clamp(Velocity.Length() * 10.0f, 0.1f, 5.0f) * deltaTime; if (networkUpdateTimer < 0.0f) { networkUpdateTimer = 1.0f; } - + } public void ApplyForce(Vector2 force) @@ -867,7 +871,7 @@ namespace Barotrauma subBorders.Inflate(500.0f, 500.0f); - if (subBorders.Contains(position)) return sub; + if (subBorders.Contains(position)) return sub; } return null; @@ -875,9 +879,18 @@ namespace Barotrauma //saving/loading ---------------------------------------------------- + public static void AddToSavedSubs(Submarine sub) + { + savedSubmarines.Add(sub); + } + public static void RefreshSavedSubs() { - SavedSubmarines.Clear(); + for (int i = savedSubmarines.Count - 1; i>= 0; i--) + { + savedSubmarines[i].Dispose(); + } + System.Diagnostics.Debug.Assert(savedSubmarines.Count == 0); if (!Directory.Exists(SavePath)) { @@ -921,7 +934,7 @@ namespace Barotrauma foreach (string path in filePaths) { - SavedSubmarines.Add(new Submarine(path)); + savedSubmarines.Add(new Submarine(path)); } } @@ -971,7 +984,7 @@ namespace Barotrauma catch (Exception e) { - DebugConsole.ThrowError("Loading submarine \"" + file + "\" failed! ("+e.Message+")"); + DebugConsole.ThrowError("Loading submarine \"" + file + "\" failed! (" + e.Message + ")"); return null; } } @@ -1147,12 +1160,12 @@ namespace Barotrauma Submarine sub = new Submarine(element.GetAttributeString("name", ""), "", false); sub.Load(unloadPrevious, element); - return sub; + return sub; } public static Submarine Load(string fileName, bool unloadPrevious) { - return Load(fileName, SavePath, unloadPrevious); + return Load(fileName, SavePath, unloadPrevious); } public static Submarine Load(string fileName, string folder, bool unloadPrevious) @@ -1285,6 +1298,15 @@ namespace Barotrauma DockedTo.Clear(); } + public void Dispose() + { + savedSubmarines.Remove(this); +#if CLIENT + PreviewImage.Remove(); + PreviewImage = null; +#endif + } + public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null) { msg.Write(ID); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs b/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs index f119d3f26..3ce6c9153 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/FileTransfer/FileSender.cs @@ -271,7 +271,7 @@ namespace Barotrauma.Networking 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); + var requestedSubmarine = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.Hash == fileHash); if (requestedSubmarine != null) { diff --git a/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs b/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs index c78a1bede..300198353 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs @@ -93,7 +93,7 @@ namespace Barotrauma { case VoteType.Sub: string subName = inc.ReadString(); - Submarine sub = Submarine.SavedSubmarines.Find(s => s.Name == subName); + Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName); sender.SetVote(voteType, sub); #if CLIENT UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType); From f25fe6b504d0076cf31ba658a71be65e56829f62 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 14:36:00 +0300 Subject: [PATCH 05/29] Added some error checking & debug logging to Door.PushCharactersAway to diagnose why Math.Sign is throwing ArithmeticExceptions (see #497). --- .../Source/Items/Components/Door.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs index 20e3900d5..3cf5947a8 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs @@ -349,6 +349,12 @@ namespace Barotrauma.Items.Components private void PushCharactersAway() { + if (!MathUtils.IsValid(item.SimPosition)) + { + DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the door is not valid (" + item.SimPosition + ")"); + return; + } + //push characters out of the doorway when the door is closing/opening Vector2 simPos = ConvertUnits.ToSimUnits(new Vector2(item.Rect.X, item.Rect.Y)); @@ -360,6 +366,12 @@ namespace Barotrauma.Items.Components foreach (Character c in Character.CharacterList) { + if (!c.Enabled) continue; + if (!MathUtils.IsValid(c.SimPosition)) + { + DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + c.SimPosition + ")"); + continue; + } int dir = isHorizontal ? Math.Sign(c.SimPosition.Y - item.SimPosition.Y) : Math.Sign(c.SimPosition.X - item.SimPosition.X); List bodies = c.AnimController.Limbs.Select(l => l.body).ToList(); @@ -372,13 +384,11 @@ namespace Barotrauma.Items.Components if (isHorizontal) { if (body.SimPosition.X < simPos.X || body.SimPosition.X > simPos.X + simSize.X) continue; - diff = body.SimPosition.Y - item.SimPosition.Y; } else { if (body.SimPosition.Y > simPos.Y || body.SimPosition.Y < simPos.Y - simSize.Y) continue; - diff = body.SimPosition.X - item.SimPosition.X; } From 30a453191f79c7ad3f91c9d8db1416ac17ddb90b Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 18 Jul 2018 15:07:21 +0300 Subject: [PATCH 06/29] Added "VulnerableToEMP" property to Powered. Can be edited in sub editor. Reactors and relays are not affected by EMP by default. Closes #495 --- .../Content/Items/Electricity/signalitems.xml | 2 +- .../BarotraumaShared/Content/Items/Reactor/reactor.xml | 2 +- .../Source/Items/Components/Power/Powered.cs | 10 ++++++++-- Barotrauma/BarotraumaShared/Source/Map/Explosion.cs | 10 ++++------ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml b/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml index 0c01875bd..58f1a40c6 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml @@ -261,7 +261,7 @@ - + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml b/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml index 840b56a18..eb7db5017 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml @@ -21,7 +21,7 @@ - + diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/Powered.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/Powered.cs index d56c18ff2..02924fb61 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/Powered.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/Powered.cs @@ -33,8 +33,7 @@ namespace Barotrauma.Items.Components get { return powerConsumption; } set { powerConsumption = value; } } - - + [Serialize(false, true)] public override bool IsActive { @@ -60,6 +59,13 @@ namespace Barotrauma.Items.Components set { voltage = Math.Max(0.0f, value); } } + [Editable(ToolTip = "Can the item be damaged by electomagnetic pulses."), Serialize(true, true)] + public bool VulnerableToEMP + { + get; + set; + } + public Powered(Item item, XElement element) : base(item, element) { diff --git a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs index a11ce2b95..121fe5417 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs @@ -78,15 +78,13 @@ namespace Barotrauma { float distSqr = Vector2.DistanceSquared(item.WorldPosition, worldPosition); if (distSqr > displayRangeSqr) continue; - - //ignore reactors (don't want to blow them up) - if (item.GetComponent() != null) continue; - + float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange; //damage repairable power-consuming items - var powerTransfer = item.GetComponent(); - if (powerTransfer != null && item.FixRequirements.Count > 0) + var powered = item.GetComponent(); + if (powered == null || !powered.VulnerableToEMP) continue; + if (item.FixRequirements.Count > 0) { item.Condition -= 100 * empStrength * distFactor; } From c901b75ff166f05dcc1abd637fc05c9ae1633a06 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 19 Jul 2018 10:47:39 +0300 Subject: [PATCH 07/29] Fixed round ending tickbox not being visible client-side if the client is not controlling character (despite servers now allowing votes from players who've spawned at least once during the round). Closes #500 --- .../Source/Characters/CharacterNetworking.cs | 2 ++ .../Source/Networking/GameClient.cs | 26 ++++++++++++++++--- .../Source/Networking/GameServer.cs | 9 +++++++ .../Source/Networking/NetworkMember.cs | 14 ---------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs index 7fe1028ac..9db7409d8 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -188,6 +188,7 @@ namespace Barotrauma controlled = this; IsRemotePlayer = false; + GameMain.Client.HasSpawned = true; GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; } @@ -286,6 +287,7 @@ namespace Barotrauma if (GameMain.Client.ID == ownerId) { + GameMain.Client.HasSpawned = true; GameMain.Client.Character = character; Controlled = character; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 5e097dffd..e58636d35 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -44,6 +44,9 @@ namespace Barotrauma.Networking private FileReceiver fileReceiver; + //has the client been given a character to control this round + public bool HasSpawned; + public byte ID { get { return myID; } @@ -480,7 +483,7 @@ namespace Barotrauma.Networking if (gameStarted && Screen.Selected == GameMain.GameScreen) { - endVoteTickBox.Visible = Voting.AllowEndVoting && myCharacter != null; + endVoteTickBox.Visible = Voting.AllowEndVoting && HasSpawned; if (respawnManager != null) { @@ -666,6 +669,7 @@ namespace Barotrauma.Networking private IEnumerable StartGame(NetIncomingMessage inc) { if (Character != null) Character.Remove(); + HasSpawned = false; GameMain.LightManager.LightingEnabled = true; @@ -1281,6 +1285,23 @@ namespace Barotrauma.Networking { base.Draw(spriteBatch); + if (Screen.Selected == GameMain.GameScreen && !GUI.DisableHUD) + { + if (EndVoteCount > 0) + { + if (!HasSpawned) + { + GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40), + "Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont); + } + else + { + GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 140.0f, 40), + "Votes (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont); + } + } + } + if (fileReceiver != null && fileReceiver.ActiveTransfers.Count > 0) { Vector2 pos = new Vector2(GameMain.NetLobbyScreen.InfoFrame.Rect.X, GameMain.GraphicsHeight - 35); @@ -1564,14 +1585,13 @@ namespace Barotrauma.Networking { if (!gameStarted) return false; - if (!Voting.AllowEndVoting || myCharacter==null) + if (!Voting.AllowEndVoting || !HasSpawned) { tickBox.Visible = false; return false; } Vote(VoteType.EndRound, tickBox.Selected); - return false; } } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs index f146214e8..87919d6b8 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs @@ -63,6 +63,15 @@ namespace Barotrauma.Networking log.LogFrame.Draw(spriteBatch); } + if (Screen.Selected == GameMain.GameScreen && !GUI.DisableHUD) + { + if (EndVoteCount > 0) + { + GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40), + "Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont); + } + } + if (!ShowNetStats) return; GUI.Font.DrawString(spriteBatch, "Unique Events: " + entityEventManager.UniqueEvents.Count, new Vector2(10, 50), Color.White); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs index cfc4b7f22..1bdd6110b 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs @@ -119,20 +119,6 @@ namespace Barotrauma.Networking inGameHUD.Draw(spriteBatch); - if (EndVoteCount > 0) - { - if (GameMain.NetworkMember.myCharacter == null) - { - GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 180.0f, 40), - "Votes to end the round (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont); - } - else - { - GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 140.0f, 40), - "Votes (y/n): " + EndVoteCount + "/" + (EndVoteMax - EndVoteCount), Color.White, null, 0, GUI.SmallFont); - } - } - if (respawnManager != null) { string respawnInfo = ""; From 8cd79190096a5299cbae93ee5067ba54f4a5426a Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 19 Jul 2018 17:42:03 +0300 Subject: [PATCH 08/29] Removed unused BanClient method --- .../Source/Networking/GameServer.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 6dbd84ce9..60b587a89 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -1583,24 +1583,7 @@ namespace Barotrauma.Networking BanClient(client, reason, range, duration); } - - public void BanClient(NetConnection conn, string reason, bool range = false, TimeSpan? duration = null) - { - Client client = connectedClients.Find(c => c.Connection == conn); - if (client == null) - { - conn.Disconnect("You have been banned from the server"); - if (!banList.IsBanned(conn.RemoteEndPoint.Address.ToString())) - { - banList.BanPlayer("Unnamed", conn.RemoteEndPoint.Address.ToString(), reason, duration); - } - } - else - { - BanClient(client, reason, range); - } - } - + public void BanClient(Client client, string reason, bool range = false, TimeSpan? duration = null) { if (client == null) return; From f1c4bd3c676fa56d521565749387cb1659f74c5f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 19 Jul 2018 21:13:18 +0300 Subject: [PATCH 09/29] - Some of the non-game-crashing error messages are sent to GameAnalytics. - Changed crash severity from Error to Critical. - Exception handling when loading submarine preview images. - Checking if position is valid in Ragdoll.SetPosition. --- .../Source/Characters/Animation/Ragdoll.cs | 3 +++ .../Source/Networking/GameClient.cs | 25 +++++++++++-------- .../ClientEntityEventManager.cs | 3 +++ Barotrauma/BarotraumaClient/Source/Program.cs | 2 +- .../Source/Screens/NetLobbyScreen.cs | 16 ++++++++++-- .../Source/Sounds/OggStream.cs | 4 +++ .../Source/Characters/AI/AITarget.cs | 6 +++++ .../Source/Characters/Animation/Ragdoll.cs | 15 +++++++++++ .../BarotraumaShared/Source/DebugConsole.cs | 11 +++++++- .../Source/GameAnalyticsManager.cs | 15 +++++++++++ .../Source/Items/Components/Door.cs | 6 +++++ .../BarotraumaShared/Source/Map/Submarine.cs | 14 +++++++++-- .../NetEntityEvent/NetEntityEventManager.cs | 6 +++++ 13 files changed, 109 insertions(+), 17 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index 309920928..6b9d32c9e 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -81,6 +81,9 @@ namespace Barotrauma if (Limbs == null) { DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace); + GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace); return; } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index e58636d35..adbc146eb 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -1020,29 +1020,32 @@ namespace Barotrauma.Networking ChatMessage.ClientRead(inc); break; default: - DebugConsole.ThrowError("Error while reading update from server (unknown object header \""+objHeader+"\"!)"); - if (prevObjHeader != null) + List errorLines = new List { - DebugConsole.ThrowError("Previous object type: " + prevObjHeader.ToString()); - } - else - { - DebugConsole.ThrowError("Error occurred on the very first object!"); - } - DebugConsole.ThrowError("Previous object was " + (inc.Position - prevBitPos) + " bits long (" + (inc.PositionInBytes - prevBytePos) + " bytes)"); + "Error while reading update from server (unknown object header \"" + objHeader + "\"!)", + prevObjHeader != null ? "Previous object type: " + prevObjHeader.ToString() : "Error occurred on the very first object!", + "Previous object was " + (inc.Position - prevBitPos) + " bits long (" + (inc.PositionInBytes - prevBytePos) + " bytes)" + }; if (prevObjHeader == ServerNetObject.ENTITY_EVENT || prevObjHeader == ServerNetObject.ENTITY_EVENT_INITIAL) { foreach (IServerSerializable ent in entities) { if (ent == null) { - DebugConsole.ThrowError(" - NULL"); + errorLines.Add(" - NULL"); continue; } Entity e = ent as Entity; - DebugConsole.ThrowError(" - "+e.ToString()); + errorLines.Add(" - " + e.ToString()); } } + + foreach (string line in errorLines) + { + DebugConsole.ThrowError(line); + } + GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, string.Join("\n", errorLines)); + DebugConsole.ThrowError("Writing object data to \"crashreport_object.bin\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues"); FileStream fl = File.Open("crashreport_object.bin", FileMode.Create); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs index 2ea912a2f..4beda97e2 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs @@ -191,6 +191,9 @@ namespace Barotrauma.Networking if (GameSettings.VerboseLogging) { DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e); + GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(), + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to read event for entity \"" + entity.ToString() + "\"!\n" + e.StackTrace); } msg.Position = msgPosition + msgLength * 8; } diff --git a/Barotrauma/BarotraumaClient/Source/Program.cs b/Barotrauma/BarotraumaClient/Source/Program.cs index 4cb2af6c2..2e3f81929 100644 --- a/Barotrauma/BarotraumaClient/Source/Program.cs +++ b/Barotrauma/BarotraumaClient/Source/Program.cs @@ -203,7 +203,7 @@ namespace Barotrauma if (GameSettings.SendUserStatistics) { CrashMessageBox( "A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers."); - GameAnalytics.AddErrorEvent(EGAErrorSeverity.Error, crashReport); + GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport); GameAnalytics.OnStop(); } else diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 287edb042..0f9b9ad1b 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -737,8 +737,20 @@ namespace Barotrauma //hash will be null if opening the sub file failed -> don't select the sub if (string.IsNullOrWhiteSpace(hash)) { - (component as GUITextBlock).TextColor = Color.DarkRed * 0.8f; - component.CanBeFocused = false; + if (component is GUITextBlock textBlock) + { + textBlock.TextColor = Color.DarkRed * 0.8f; + textBlock.CanBeFocused = false; + } + else + { + DebugConsole.ThrowError("Failed to select submarine. Selected GUIComponent was of the type \"" + (component == null ? "null" : component.GetType().ToString()) + "\"."); + GameAnalyticsManager.AddErrorEventOnce( + "NetLobbyScreen.SelectSub:InvalidComponent", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to select submarine. Selected GUIComponent was of the type \"" + (component == null ? "null" : component.GetType().ToString()) + "\"."); + } + StartButton.Enabled = false; diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs index 8f88dfbb8..6f761edd3 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs @@ -55,6 +55,10 @@ namespace Barotrauma.Sounds #else DebugConsole.NewMessage("OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace, Microsoft.Xna.Framework.Color.Red); #endif + GameAnalyticsManager.AddErrorEventOnce( + "OggStream.Check:"+ AL.GetErrorString(error), + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace); } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs index 87f40912c..d857cf3b6 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs @@ -38,6 +38,9 @@ namespace Barotrauma #if DEBUG DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace); #endif + GameAnalyticsManager.AddErrorEventOnce("AITarget.WorldPosition:EntityRemoved", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Attempted to access a removed AITarget\n" + Environment.StackTrace); return Vector2.Zero; } @@ -54,6 +57,9 @@ namespace Barotrauma #if DEBUG DebugConsole.ThrowError("Attempted to access a removed AITarget\n" + Environment.StackTrace); #endif + GameAnalyticsManager.AddErrorEventOnce("AITarget.WorldPosition:EntityRemoved", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Attempted to access a removed AITarget\n" + Environment.StackTrace); return Vector2.Zero; } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index c9a371e76..3a5f28887 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -25,6 +25,11 @@ namespace Barotrauma if (limbs == null) { DebugConsole.ThrowError("Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this)); + GameAnalyticsManager.AddErrorEventOnce( + "Ragdoll.Limbs:AccessRemoved", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this)); + return new Limb[0]; } return limbs; @@ -1165,6 +1170,16 @@ namespace Barotrauma public void SetPosition(Vector2 simPosition, bool lerp = false) { + if (!MathUtils.IsValid(simPosition)) + { + DebugConsole.ThrowError("Attempted to move a ragdoll (" + character.Name + ") to an invalid position (" + simPosition + "). " + Environment.StackTrace); + GameAnalyticsManager.AddErrorEventOnce( + "Ragdoll.SetPosition:InvalidPosition", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Attempted to move a ragdoll (" + character.Name + ") to an invalid position (" + simPosition + "). " + Environment.StackTrace); + return; + } + Vector2 limbMoveAmount = simPosition - MainLimb.SimPosition; Collider.SetTransform(simPosition, Collider.Rotation); diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 2b65dccf9..078ef2755 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -1898,7 +1898,16 @@ namespace Barotrauma if (string.IsNullOrWhiteSpace(command)) return; string[] splitCommand = SplitCommand(command); - + if (splitCommand.Length == 0) + { + DebugConsole.ThrowError("Failed to execute command \"" + command + "\"!"); + GameAnalyticsManager.AddErrorEventOnce( + "DebugConsole.ExecuteCommand:LengthZero", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to execute command \"" + command + "\"!"); + return; + } + if (!splitCommand[0].ToLowerInvariant().Equals("admin")) { NewMessage(command, Color.White, true); diff --git a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs index 81374dab6..e96489c16 100644 --- a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs @@ -1,5 +1,6 @@ using GameAnalyticsSDK.Net; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; @@ -9,6 +10,8 @@ namespace Barotrauma { public static class GameAnalyticsManager { + private static HashSet sentEventIdentifiers = new HashSet(); + public static void Init() { #if DEBUG @@ -47,5 +50,17 @@ namespace Barotrauma contentPackageName.Replace(":", "").Substring(0, Math.Min(32, contentPackageName.Length))); } } + + /// + /// Adds an error event to GameAnalytics if an event with the same identifier has not been added yet. + /// + public static void AddErrorEventOnce(string identifier, EGAErrorSeverity errorSeverity, string message) + { + if (!GameSettings.SendUserStatistics) return; + if (sentEventIdentifiers.Contains(identifier)) return; + + GameAnalytics.AddErrorEvent(errorSeverity, message); + sentEventIdentifiers.Add(identifier); + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs index 3cf5947a8..b3c8a5b03 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs @@ -352,6 +352,8 @@ namespace Barotrauma.Items.Components if (!MathUtils.IsValid(item.SimPosition)) { DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the door is not valid (" + item.SimPosition + ")"); + GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:DoorPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to push a character out of a doorway - position of the door is not valid (" + item.SimPosition + ")."); return; } @@ -370,6 +372,10 @@ namespace Barotrauma.Items.Components if (!MathUtils.IsValid(c.SimPosition)) { DebugConsole.ThrowError("Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + c.SimPosition + ")"); + GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:CharacterPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + c.SimPosition + ")." + + " Removed: " + c.Removed + + " Remoteplayer: " + c.IsRemotePlayer); continue; } int dir = isHorizontal ? Math.Sign(c.SimPosition.Y - item.SimPosition.Y) : Math.Sign(c.SimPosition.X - item.SimPosition.X); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index e5ade2ae9..d291304b5 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -300,9 +300,19 @@ namespace Barotrauma string previewImageData = doc.Root.GetAttributeString("previewimage", ""); if (!string.IsNullOrEmpty(previewImageData)) { - using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData))) + try { - PreviewImage = new Sprite(TextureLoader.FromStream(mem), null, null); + 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 diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs index fad368b6e..eafb6fb1b 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs @@ -30,6 +30,9 @@ namespace Barotrauma.Networking catch (Exception exception) { DebugConsole.ThrowError("Failed to write an event for the entity \"" + e.Entity + "\"", exception); + GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:WriteFailed" + e.Entity.ToString(), + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to write an event for the entity \"" + e.Entity + "\"\n" + exception.StackTrace); //write an empty event to avoid messing up IDs //(otherwise the clients might read the next event in the message and think its ID @@ -49,6 +52,9 @@ namespace Barotrauma.Networking if (tempEventBuffer.LengthBytes > 255) { DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); + GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:TooLong" + e.Entity.ToString(), + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); } //the ID has been taken by another entity (the original entity has been removed) -> write an empty event From e4e610b35effe6942d3264f79b370ee22366d29e Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 19 Jul 2018 22:13:09 +0300 Subject: [PATCH 10/29] Added exception handling to GameSettings saving --- Barotrauma/BarotraumaShared/Source/GameSettings.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index fbc3b2fe8..9acd0b434 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -402,7 +402,16 @@ namespace Barotrauma new XAttribute("gender", characterGender)); doc.Root.Add(playerElement); - doc.Save(filePath); + try + { + doc.Save(filePath); + } + catch (Exception e) + { + DebugConsole.ThrowError("Saving game settings failed.", e); + GameAnalyticsManager.AddErrorEventOnce("GameSettings.Save:SaveFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace); + } } private IEnumerable ApplyUnsavedChanges() From f822e772418d4ee77f91066f2a69309aa30fb5b8 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 19 Jul 2018 22:21:08 +0300 Subject: [PATCH 11/29] Checking if the position is valid in Ragdoll.FindHull --- .../Source/Characters/Animation/Ragdoll.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 3a5f28887..3a9fbcd73 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -744,7 +744,15 @@ namespace Barotrauma public void FindHull(Vector2? worldPosition = null, bool setSubmarine = true) { - Vector2 findPos = worldPosition==null ? this.WorldPosition : (Vector2)worldPosition; + Vector2 findPos = worldPosition == null ? this.WorldPosition : (Vector2)worldPosition; + if (!MathUtils.IsValid(findPos)) + { + GameAnalyticsManager.AddErrorEventOnce( + "Ragdoll.FindHull:InvalidPosition", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Attempted to find a hull at an invalid position (" + findPos + ")\n" + Environment.StackTrace); + return; + } Hull newHull = Hull.FindHull(findPos, currentHull); From 9e69216c527f921107aab1c5d783e361a156d2a2 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 01:09:55 +0300 Subject: [PATCH 12/29] Server validates the cursor positions clients send for a console command before using them! --- Barotrauma/BarotraumaShared/Source/DebugConsole.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 078ef2755..1ad87c716 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -1983,6 +1983,13 @@ namespace Barotrauma { GameMain.Server.SendConsoleMessage("Command \"" + splitCommand[0] + "\" not found.", client); return; + } + + if (!MathUtils.IsValid(cursorWorldPos)) + { + GameMain.Server.SendConsoleMessage("Could not execute command \"" + command + "\" - invalid cursor position.", client); + NewMessage(client.Name + " attempted to execute the console command \"" + command + "\" with invalid cursor position.", Color.White); + return; } try From 9b4247a1477028044b39c9304feabfac09ee7738 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 01:10:02 +0300 Subject: [PATCH 13/29] v0.8.1.6 --- Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 40fceb2b3..2f1006a44 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.5")] -[assembly: AssemblyFileVersion("0.8.1.5")] +[assembly: AssemblyVersion("0.8.1.6")] +[assembly: AssemblyFileVersion("0.8.1.6")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 66089601e..03badd491 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.5")] -[assembly: AssemblyFileVersion("0.8.1.5")] +[assembly: AssemblyVersion("0.8.1.6")] +[assembly: AssemblyFileVersion("0.8.1.6")] From e1539b76cdba8913010305945d79c8485d98be20 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 09:53:14 +0300 Subject: [PATCH 14/29] v0.8.1.6 changelog (forgot from the previous commit) --- Barotrauma/BarotraumaShared/changelog.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 3c33067bd..6dc3f75df 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,23 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.6 +--------------------------------------------------------------------------------------------------------- + +- Fixed a memory leak in submarine preview images which caused crashes in the server lobby screen and +submarine editor. +- Fixed clients not seeing the "vote to end the round" tickbox if they don't have a character assigned to +them (despite the server allowing voting if the client has had a character earlier during the round). +- Fixed clients being able to crash servers if they had the permission to use console commands that +use the position of the client's cursor. +- Fixed crashing if a wire is used by a statuseffect (for example if a detonator tries to trigger a wire +contained inside it). +- Fixed GameAnalytics being stopped if the dedicated server is restarted with the "restart" console command.- +- Fixed wiring items outside the submarine. +- Fixed chatbox discarding the second chat message instead of the first one when the maximum number of +chat messages is reached. +- Some error checking and debug logging to diagnose and prevent a crash caused by doors pushing characters away. +- The spawnitem command doesn't require multi-word item names to be surrounded with quotes anymore. +- Added the option to make powered items immune to electromagnetic pulses. + --------------------------------------------------------------------------------------------------------- v0.8.1.5 --------------------------------------------------------------------------------------------------------- From a712ec67566771f401145539117f54cd460df26a Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 09:53:31 +0300 Subject: [PATCH 15/29] Fixed null reference exception when trying to dispose a sub with no preview image. Closes #503 --- Barotrauma/BarotraumaShared/Source/Map/Submarine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index d291304b5..0568cfcd4 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -1312,7 +1312,7 @@ namespace Barotrauma { savedSubmarines.Remove(this); #if CLIENT - PreviewImage.Remove(); + PreviewImage?.Remove(); PreviewImage = null; #endif } From 9963836c084cc1b943fddfd0edb37e6a4a79cb3a Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 10:21:22 +0300 Subject: [PATCH 16/29] v0.8.1.7 --- Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaShared/changelog.txt | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 2f1006a44..f6e89a9a8 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.6")] -[assembly: AssemblyFileVersion("0.8.1.6")] +[assembly: AssemblyVersion("0.8.1.7")] +[assembly: AssemblyFileVersion("0.8.1.7")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 03badd491..da903abca 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.6")] -[assembly: AssemblyFileVersion("0.8.1.6")] +[assembly: AssemblyVersion("0.8.1.7")] +[assembly: AssemblyFileVersion("0.8.1.7")] diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 6dc3f75df..ab208f888 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,9 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.7 +--------------------------------------------------------------------------------------------------------- + +- Fixed crashes when trying to load submarines in the sub editor. + --------------------------------------------------------------------------------------------------------- v0.8.1.6 --------------------------------------------------------------------------------------------------------- From f13b1b4d8445bd2fe671b66df447b8e05d27b55f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 11:36:22 +0300 Subject: [PATCH 17/29] Fixed camera ScreenToWorld & WorldToScreen returning invalid values when Camera.UpdateTransform has only been called once, because interpolated zoom value is initially 0 which messes up the transformation matrices. Closes #504 --- Barotrauma/BarotraumaClient/Source/Camera.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Camera.cs b/Barotrauma/BarotraumaClient/Source/Camera.cs index 487bb3b87..6b5da39dc 100644 --- a/Barotrauma/BarotraumaClient/Source/Camera.cs +++ b/Barotrauma/BarotraumaClient/Source/Camera.cs @@ -99,7 +99,7 @@ namespace Barotrauma public Camera() { - zoom = 1.0f; + zoom = prevZoom = 1.0f; rotation = 0.0f; position = Vector2.Zero; @@ -112,7 +112,7 @@ namespace Barotrauma viewMatrix = Matrix.CreateTranslation(new Vector3(GameMain.GraphicsWidth / 2.0f, GameMain.GraphicsHeight / 2.0f, 0)); - UpdateTransform(); + UpdateTransform(false); } public Vector2 TargetPos From 8e03ac928444477a5ac1dde2bc84907b8b2a42dc Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 11:36:53 +0300 Subject: [PATCH 18/29] Fixed nullref exceptions in CharacterHUD & RuinGenerator --- Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs | 2 +- .../BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs index 295d54d8c..bf6677e4c 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs @@ -32,7 +32,7 @@ namespace Barotrauma public static void TakeDamage(float amount) { - healthBar.Flash(); + healthBar?.Flash(); damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 1.0f); } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs index 1f7e758dd..ad9c9a4d0 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs @@ -423,6 +423,7 @@ namespace Barotrauma.RuinGeneration Alignment[] alignments = new Alignment[] { Alignment.Top, Alignment.Bottom, Alignment.Right, Alignment.Left, Alignment.Center }; var prop = RuinStructure.GetRandom(RuinStructureType.Prop, alignments[Rand.Int(alignments.Length, Rand.RandSync.Server)]); + if (prop == null) continue; Vector2 size = (prop.Prefab is StructurePrefab) ? ((StructurePrefab)prop.Prefab).Size : Vector2.Zero; From 49c6b177e33e7ec5506de7471d2ca0899dae16ad Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 12:05:13 +0300 Subject: [PATCH 19/29] Added wrapper methods that check if user statistics are enabled to GameAnalyticsManager --- Barotrauma/BarotraumaClient/Source/GUI/GUI.cs | 9 ++---- .../Source/Screens/LobbyScreen.cs | 2 +- .../Source/Screens/MainMenuScreen.cs | 2 +- .../Source/Screens/NetLobbyScreen.cs | 2 +- .../Source/Screens/SubEditorScreen.cs | 2 +- .../Source/Characters/Character.cs | 2 +- .../Source/GameAnalyticsManager.cs | 30 +++++++++++++++++++ .../Source/GameSession/GameSession.cs | 19 +++++------- .../Source/Networking/GameServer.cs | 11 +++---- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index 162a109f8..91d742630 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -214,12 +214,9 @@ namespace Barotrauma if (GameMain.GameSession != null) { - if (GameSettings.SendUserStatistics) - { - Mission mission = GameMain.GameSession.Mission; - GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave")); - GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed"))); - } + Mission mission = GameMain.GameSession.Mission; + GameAnalyticsManager.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave")); + GameAnalyticsManager.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed"))); GameMain.GameSession = null; } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/LobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/LobbyScreen.cs index 41ce03dfd..a8df21efa 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/LobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/LobbyScreen.cs @@ -88,7 +88,7 @@ namespace Barotrauma campaignUI.OnLocationSelected = SelectLocation; campaignUI.UpdateCharacterLists(); - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("singleplayer"); + GameAnalyticsManager.SetCustomDimension01("singleplayer"); } public override void AddToGUIUpdateList() diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index 6785b2c01..f375ee30d 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -143,7 +143,7 @@ namespace Barotrauma SelectTab(null, 0); - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01(""); + GameAnalyticsManager.SetCustomDimension01(""); } public bool SelectTab(GUIButton button, object obj) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 0f9b9ad1b..dbc53fa2f 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -501,7 +501,7 @@ namespace Barotrauma } } - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("multiplayer"); + GameAnalyticsManager.SetCustomDimension01("multiplayer"); if (GameModePreset.list.Count > 0 && modeList.Selected == null) modeList.Select(0); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs index 12659034f..c5d6d6bff 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs @@ -349,7 +349,7 @@ namespace Barotrauma cam.UpdateTransform(); - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("editor"); + GameAnalyticsManager.SetCustomDimension01("editor"); } public override void Deselect() diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index dbf3e7e0c..1242b7aa6 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -1960,7 +1960,7 @@ namespace Barotrauma characterType = "Enemy"; else if (AIController is HumanAIController) characterType = "AICrew"; - GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeath); + GameAnalyticsManager.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeath); } if (OnDeath != null) OnDeath(this, causeOfDeath); diff --git a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs index e96489c16..28eb2d335 100644 --- a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs @@ -62,5 +62,35 @@ namespace Barotrauma GameAnalytics.AddErrorEvent(errorSeverity, message); sentEventIdentifiers.Add(identifier); } + + public static void AddDesignEvent(string eventID) + { + if (!GameSettings.SendUserStatistics) return; + GameAnalytics.AddDesignEvent(eventID); + } + + public static void AddDesignEvent(string eventID, double value) + { + if (!GameSettings.SendUserStatistics) return; + GameAnalytics.AddDesignEvent(eventID, value); + } + + public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01) + { + if (!GameSettings.SendUserStatistics) return; + GameAnalytics.AddProgressionEvent(progressionStatus, progression01); + } + + public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02) + { + if (!GameSettings.SendUserStatistics) return; + GameAnalytics.AddProgressionEvent(progressionStatus, progression01, progression02); + } + + public static void SetCustomDimension01(string dimension) + { + if (!GameSettings.SendUserStatistics) return; + GameAnalytics.SetCustomDimension01(dimension); + } } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index ef9c4f3fb..61394b4c6 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -234,13 +234,11 @@ namespace Barotrauma campaign.CargoManager.CreateItems(); } } - - if (GameSettings.SendUserStatistics) - { - GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Submarine:" + submarine.Name); - GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start, + + GameAnalyticsManager.AddDesignEvent("Submarine:" + submarine.Name); + GameAnalyticsManager.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start, GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); - } + #if CLIENT roundSummary = new RoundSummary(this); @@ -253,11 +251,10 @@ namespace Barotrauma public void EndRound(string endMessage) { if (Mission != null) Mission.End(); - if (GameSettings.SendUserStatistics) - { - GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent((Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail, - GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); - } + GameAnalyticsManager.AddProgressionEvent( + (Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail, + GameMode.Name, + (Mission == null ? "None" : Mission.GetType().ToString())); #if CLIENT if (roundSummary != null) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 60b587a89..a0da30a20 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -209,7 +209,7 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.RandomizeSettings(); started = true; - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:Start"); + GameAnalyticsManager.AddDesignEvent("GameServer:Start"); yield return CoroutineStatus.Success; } @@ -1370,7 +1370,7 @@ namespace Barotrauma.Networking } } - if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled")); + GameAnalyticsManager.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled")); SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClients); @@ -2249,11 +2249,8 @@ namespace Barotrauma.Networking Log("Shutting down the server...", ServerLog.MessageType.ServerMessage); log.Save(); } - - if (GameSettings.SendUserStatistics) - { - GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:ShutDown"); - } + + GameAnalyticsManager.AddDesignEvent("GameServer:ShutDown"); server.Shutdown("The server has been shut down"); } } From 15331c58bb0193fd4d5cca8a934885d2cfe1fdfe Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 2 Jul 2018 16:04:55 +0300 Subject: [PATCH 20/29] Cherry-picked fa84c5b (ragdoll optimization) --- .../Source/Characters/Animation/Ragdoll.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 3a9fbcd73..869180621 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -92,7 +92,9 @@ namespace Barotrauma protected List collider; protected int colliderIndex = 0; - + + private Category prevCollisionCategory = Category.None; + public PhysicsBody Collider { get @@ -274,11 +276,7 @@ namespace Barotrauma get { return ignorePlatforms; } set { - if (ignorePlatforms == value) return; ignorePlatforms = value; - - UpdateCollisionCategories(); - } } @@ -812,10 +810,7 @@ namespace Barotrauma } CurrentHull = newHull; - - character.Submarine = currentHull == null ? null : currentHull.Submarine; - - UpdateCollisionCategories(); + character.Submarine = currentHull?.Submarine; } public void Teleport(Vector2 moveAmount, Vector2 velocityChange) @@ -855,7 +850,10 @@ namespace Barotrauma Category collisionCategory = (ignorePlatforms) ? wall | Physics.CollisionProjectile | Physics.CollisionStairs : wall | Physics.CollisionProjectile | Physics.CollisionPlatform | Physics.CollisionStairs; - + + if (collisionCategory == prevCollisionCategory) return; + prevCollisionCategory = collisionCategory; + Collider.CollidesWith = collisionCategory; foreach (Limb limb in Limbs) @@ -881,6 +879,7 @@ namespace Barotrauma UpdateNetPlayerPosition(deltaTime); CheckDistFromCollider(); + UpdateCollisionCategories(); Vector2 flowForce = Vector2.Zero; @@ -1268,8 +1267,6 @@ namespace Barotrauma { //set the position of the ragdoll to make sure limbs don't get stuck inside walls when re-enabling collisions SetPosition(Collider.SimPosition, true); - - UpdateCollisionCategories(); collisionsDisabled = false; } } From e7e7d321236155f3a8bd0a7085872709edf67919 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 20 Jun 2018 15:55:23 +0300 Subject: [PATCH 21/29] Cherry-picked 0ff9a3d (more ragdoll optimization) --- .../Source/Characters/Animation/Ragdoll.cs | 38 ++++++++----------- .../BarotraumaShared/Source/Items/Item.cs | 12 +++--- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 869180621..273a83788 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -1101,22 +1101,19 @@ namespace Barotrauma float tfloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction; float targetY = tfloorY + Collider.height * 0.5f + Collider.radius + colliderHeightFromFloor; - - if (Math.Abs(Collider.SimPosition.Y - targetY) > 0.01f && Collider.SimPosition.Y 0.01f) { - Vector2 newSpeed = Collider.LinearVelocity; - newSpeed.Y = (targetY - Collider.SimPosition.Y)*5.0f; - Collider.LinearVelocity = newSpeed; - } - else - { - Vector2 newSpeed = Collider.LinearVelocity; - newSpeed.Y = 0.0f; - Collider.LinearVelocity = newSpeed; - Vector2 newPos = Collider.SimPosition; - newPos.Y = targetY; - Collider.SetTransform(newPos, Collider.Rotation); - } + if (forceImmediate) + { + Collider.LinearVelocity = new Vector2(Collider.LinearVelocity.X, 0); + Collider.SetTransform(new Vector2(Collider.SimPosition.X, targetY), Collider.Rotation); + } + else + { + Collider.LinearVelocity = new Vector2(Collider.LinearVelocity.X, (targetY - Collider.SimPosition.Y) * 5.0f); + } + } } } } @@ -1465,22 +1462,17 @@ namespace Barotrauma private Vector2 GetFlowForce() { - Vector2 limbPos = ConvertUnits.ToDisplayUnits(Limbs[0].SimPosition); + Vector2 limbPos = Limbs[0].Position; Vector2 force = Vector2.Zero; - foreach (MapEntity e in MapEntity.mapEntityList) + foreach (Gap gap in Gap.GapList) { - Gap gap = e as Gap; - if (gap == null || gap.FlowTargetHull != currentHull || gap.LerpedFlowForce == Vector2.Zero) continue; + if (gap.Open <= 0.0f || gap.FlowTargetHull != currentHull || gap.LerpedFlowForce == Vector2.Zero) continue; Vector2 gapPos = gap.SimPosition; - float dist = Vector2.Distance(limbPos, gapPos); - force += Vector2.Normalize(gap.LerpedFlowForce) * (Math.Max(gap.LerpedFlowForce.Length() - dist, 0.0f) / 500.0f); } - - if (force.Length() > 20.0f) return force; return force; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 32da8efeb..5fe179479 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -783,12 +783,6 @@ namespace Barotrauma public override void Update(float deltaTime, Camera cam) { - if (Level.Loaded != null && WorldPosition.Y < Level.MaxEntityDepth) - { - Spawner.AddToRemoveQueue(this); - return; - } - ApplyStatusEffects(ActionType.Always, deltaTime, null); foreach (ItemComponent ic in components) @@ -851,6 +845,12 @@ namespace Barotrauma MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel)); } + + if (CurrentHull == null && body.SimPosition.Y < ConvertUnits.ToSimUnits(Level.MaxEntityDepth)) + { + Spawner.AddToRemoveQueue(this); + return; + } } UpdateNetPosition(); From bcd9fd7e5f0c50a7a2814c6524f03270a9ae624d Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 12:23:07 +0300 Subject: [PATCH 22/29] Cherry-picked de2136c (level physicsbody optimization) --- .../Source/Map/Levels/CaveGenerator.cs | 38 ++++++++----------- .../Source/Map/Levels/LevelWall.cs | 4 +- .../Source/Map/SubmarineBody.cs | 24 +++++------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs index 790e08eff..9cccfc97f 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs @@ -323,18 +323,9 @@ namespace Barotrauma //choose random edge (ignoring ones where the adjacent cell is outside limits) else { - - - //if (allowedEdges.Count==0) - //{ - // edgeIndex = Rand.Int(currentCell.edges.Count, false); - //} - //else - //{ edgeIndex = Rand.Int(allowedEdges.Count, Rand.RandSync.Server); if (mirror && edgeIndex > 0) edgeIndex = allowedEdges.Count - edgeIndex; edgeIndex = currentCell.edges.IndexOf(allowedEdges[edgeIndex]); - //} } currentCell = currentCell.edges[edgeIndex].AdjacentCell(currentCell); @@ -357,8 +348,8 @@ namespace Barotrauma return pathCells; } - - public static List GeneratePolygons(List cells, out List renderTriangles, bool setSolid=true) + + public static List GeneratePolygons(List cells, out List renderTriangles, bool setSolid = true) { renderTriangles = new List(); var bodies = new List(); @@ -366,6 +357,14 @@ namespace Barotrauma List tempVertices = new List(); List bodyPoints = new List(); + Body cellBody = new Body(GameMain.World) + { + SleepingAllowed = false, + BodyType = BodyType.Static, + CollisionCategories = Physics.CollisionLevel + }; + bodies.Add(cellBody); + for (int n = cells.Count - 1; n >= 0; n-- ) { VoronoiCell cell = cells[n]; @@ -412,14 +411,12 @@ namespace Barotrauma cell.bodyVertices.Add(bodyPoints[i]); bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]); } - - + if (cell.CellType == CellType.Empty) continue; + cellBody.UserData = cell; var triangles = MathUtils.TriangulateConvexHull(bodyPoints, ConvertUnits.ToSimUnits(cell.Center)); - - Body cellBody = new Body(GameMain.World); - + for (int i = 0; i < triangles.Count; i++) { //don't create a triangle if any of the vertices are too close to each other @@ -429,16 +426,11 @@ namespace Barotrauma Vector2.Distance(triangles[i][1], triangles[i][2]) < 0.05f) continue; Vertices bodyVertices = new Vertices(triangles[i]); - FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); + var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); + newFixture.UserData = cell; } - cellBody.UserData = cell; - cellBody.SleepingAllowed = false; - cellBody.BodyType = BodyType.Kinematic; - cellBody.CollisionCategories = Physics.CollisionLevel; - cell.body = cellBody; - bodies.Add(cellBody); } return bodies; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs index 059301862..a0445de16 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs @@ -21,7 +21,6 @@ namespace Barotrauma public LevelWall(List edgePositions, Vector2 extendAmount, Color color) { cells = new List(); - for (int i = 0; i < edgePositions.Count - 1; i++) { Vector2[] vertices = new Vector2[4]; @@ -47,8 +46,7 @@ namespace Barotrauma cells.Add(wallCell); } - List triangles; - bodies = CaveGenerator.GeneratePolygons(cells, out triangles, false); + bodies = CaveGenerator.GeneratePolygons(cells, out List triangles, false); #if CLIENT List bodyVertices = CaveGenerator.GenerateRenderVerticeList(triangles); diff --git a/Barotrauma/BarotraumaShared/Source/Map/SubmarineBody.cs b/Barotrauma/BarotraumaShared/Source/Map/SubmarineBody.cs index 6d623c73c..bdf43b42e 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/SubmarineBody.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/SubmarineBody.cs @@ -370,27 +370,22 @@ namespace Barotrauma public bool OnCollision(Fixture f1, Fixture f2, Contact contact) { - Limb limb = f2.Body.UserData as Limb; - if (limb != null) + if (f2.Body.UserData is Limb limb) { bool collision = CheckLimbCollision(contact, limb); if (collision) HandleLimbCollision(contact, limb); return collision; } - VoronoiCell cell = f2.Body.UserData as VoronoiCell; - if (cell != null) + if (f2.UserData is VoronoiCell cell) { HandleLevelCollision(contact, Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center)); return true; } - Structure structure = f2.Body.UserData as Structure; - if (structure != null) + if (f2.Body.UserData is Structure structure) { - Vector2 normal; - FixedArray2 points; - contact.GetWorldManifold(out normal, out points); + contact.GetWorldManifold(out Vector2 normal, out FixedArray2 points); if (contact.FixtureA.Body == f1.Body) { normal = -normal; @@ -400,8 +395,7 @@ namespace Barotrauma return true; } - Submarine otherSub = f2.Body.UserData as Submarine; - if (otherSub != null) + if (f2.Body.UserData is Submarine otherSub) { HandleSubCollision(contact, otherSub); return true; @@ -486,8 +480,8 @@ namespace Barotrauma levelContact.GetWorldManifold(out contactNormal, out temp); //if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal - VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ? - ((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData); + VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ? + ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData); var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center; if (Vector2.Dot(contactNormal, cellDiff) < 0) @@ -603,8 +597,8 @@ namespace Barotrauma levelContact.GetWorldManifold(out contactNormal, out temp); //if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal - VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ? - ((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData); + VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ? + ((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData); var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center; if (Vector2.Dot(contactNormal, cellDiff) < 0) From 20ed61a87937d35ad001359de94395586a2d2306 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 12:24:05 +0300 Subject: [PATCH 23/29] Version string sent to GameAnalytics includes the name and hash of the exe (makes it easier to identify events/errors from modded games), added stack trace to a ragdoll error message --- .../Source/Characters/Animation/Ragdoll.cs | 2 +- Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 273a83788..3456f0ccf 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -28,7 +28,7 @@ namespace Barotrauma GameAnalyticsManager.AddErrorEventOnce( "Ragdoll.Limbs:AccessRemoved", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, - "Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this)); + "Attempted to access a potentially removed ragdoll. Character: " + character.Name + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this) + "\n" + Environment.StackTrace); return new Limb[0]; } diff --git a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs index 28eb2d335..36cc8fbe1 100644 --- a/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs @@ -17,7 +17,6 @@ namespace Barotrauma #if DEBUG GameAnalytics.SetEnabledInfoLog(true); #endif - GameAnalytics.ConfigureBuild(GameMain.Version.ToString()); string exePath = Assembly.GetEntryAssembly().Location; string exeName = null; @@ -36,9 +35,13 @@ namespace Barotrauma DebugConsole.ThrowError("Error while calculating MD5 hash for the executable \"" + exePath + "\"", e); } + GameAnalytics.ConfigureBuild(GameMain.Version.ToString() + + (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":" + + ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash)); + GameAnalytics.AddDesignEvent("Executable:" + (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":" - + ((exeHash == null) ? "Unknown" : exeHash.ShortHash)); + + ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash)); GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor"); GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7"); From 07de2b2a0fe3ff43051022045f2ad822abba91d0 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 13:50:04 +0300 Subject: [PATCH 24/29] Fixed previous items not being cleared from multiplayer campaign UI after a round ends. Closes #505 --- Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs | 3 +++ Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs index 4751c8ac2..1e821b151 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs @@ -149,6 +149,8 @@ namespace Barotrauma null, null, Alignment.TopRight, "", frame); } + + RefreshItemTab(); } public void Update(float deltaTime) @@ -293,6 +295,7 @@ namespace Barotrauma { CreateItemFrame(ip, selectedItemList, selectedItemList.Rect.Width); } + selectedItemList.UpdateScrollBarSize(); } public void SelectTab(Tab tab) diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs b/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs index e07c7e124..580321792 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/CargoManager.cs @@ -57,6 +57,7 @@ namespace Barotrauma public void CreateItems() { CreateItems(purchasedItems); + OnItemsChanged?.Invoke(); } public static void CreateItems(List itemsToSpawn) From a61ac1716d95ba1c4dc464d0ae1fa252560c090b Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 14:17:59 +0300 Subject: [PATCH 25/29] Sending level seed & level gen errors to GameAnalytics --- .../Source/Map/Levels/CaveGenerator.cs | 10 +++++++++- .../Source/GameSession/GameSession.cs | 1 + .../Source/Map/Levels/CaveGenerator.cs | 11 ++++++++++- .../BarotraumaShared/Source/Map/Levels/Level.cs | 6 +++--- .../BarotraumaShared/Source/Map/Levels/LevelWall.cs | 6 +++--- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/CaveGenerator.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/CaveGenerator.cs index 6bc67482c..942925c27 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Levels/CaveGenerator.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/CaveGenerator.cs @@ -27,7 +27,7 @@ namespace Barotrauma return verticeList; } - public static VertexPositionTexture[] GenerateWallShapes(List cells) + public static VertexPositionTexture[] GenerateWallShapes(List cells, Level level) { float inwardThickness = 500.0f, outWardThickness = 30.0f; @@ -80,6 +80,10 @@ namespace Barotrauma #if DEBUG DebugConsole.ThrowError("Invalid left normal"); #endif + GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed, + GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, + "Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")"); + if (cell.body != null) { GameMain.World.RemoveBody(cell.body); @@ -106,6 +110,10 @@ namespace Barotrauma #if DEBUG DebugConsole.ThrowError("Invalid right normal"); #endif + GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed, + GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, + "Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")"); + if (cell.body != null) { GameMain.World.RemoveBody(cell.body); diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index 61394b4c6..91ded070f 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -236,6 +236,7 @@ namespace Barotrauma } GameAnalyticsManager.AddDesignEvent("Submarine:" + submarine.Name); + GameAnalyticsManager.AddDesignEvent("Level", ToolBox.StringToInt(level.Seed)); GameAnalyticsManager.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start, GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs index 9cccfc97f..1e08742a2 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/CaveGenerator.cs @@ -349,7 +349,7 @@ namespace Barotrauma return pathCells; } - public static List GeneratePolygons(List cells, out List renderTriangles, bool setSolid = true) + public static List GeneratePolygons(List cells, Level level, out List renderTriangles, bool setSolid = true) { renderTriangles = new List(); var bodies = new List(); @@ -428,6 +428,15 @@ namespace Barotrauma Vertices bodyVertices = new Vertices(triangles[i]); var newFixture = FixtureFactory.AttachPolygon(bodyVertices, 5.0f, cellBody); newFixture.UserData = cell; + + if (newFixture.Shape.MassData.Area < FarseerPhysics.Settings.Epsilon) + { + DebugConsole.ThrowError("Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + ")"); + GameAnalyticsManager.AddErrorEventOnce( + "CaveGenerator.GeneratePolygons:InvalidTriangle", + GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, + "Invalid triangle created by CaveGenerator (" + triangles[i][0] + ", " + triangles[i][1] + ", " + triangles[i][2] + "). Seed: " + level.Seed); + } } cell.body = cellBody; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs index 1ab021186..7d7ce68e1 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs @@ -449,11 +449,11 @@ namespace Barotrauma List cellsWithBody = new List(cells); List triangles; - bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out triangles); + bodies = CaveGenerator.GeneratePolygons(cellsWithBody, this, out triangles); #if CLIENT renderer.SetBodyVertices(CaveGenerator.GenerateRenderVerticeList(triangles).ToArray(), generationParams.WallColor); - renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells), generationParams.WallColor); + renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells, this), generationParams.WallColor); #endif TopBarrier = BodyFactory.CreateEdge(GameMain.World, @@ -700,7 +700,7 @@ namespace Barotrauma SeaFloorTopPos = bottomPositions.Max(p => p.Y); - extraWalls = new LevelWall[] { new LevelWall(bottomPositions, new Vector2(0.0f, -2000.0f), backgroundColor) }; + extraWalls = new LevelWall[] { new LevelWall(bottomPositions, new Vector2(0.0f, -2000.0f), backgroundColor, this) }; BottomBarrier = BodyFactory.CreateEdge(GameMain.World, ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)), diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs index a0445de16..b79ba05fc 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelWall.cs @@ -18,7 +18,7 @@ namespace Barotrauma private List bodies; - public LevelWall(List edgePositions, Vector2 extendAmount, Color color) + public LevelWall(List edgePositions, Vector2 extendAmount, Color color, Level level) { cells = new List(); for (int i = 0; i < edgePositions.Count - 1; i++) @@ -46,13 +46,13 @@ namespace Barotrauma cells.Add(wallCell); } - bodies = CaveGenerator.GeneratePolygons(cells, out List triangles, false); + bodies = CaveGenerator.GeneratePolygons(cells, level, out List triangles, false); #if CLIENT List bodyVertices = CaveGenerator.GenerateRenderVerticeList(triangles); SetBodyVertices(bodyVertices.ToArray(), color); - SetWallVertices(CaveGenerator.GenerateWallShapes(cells), color); + SetWallVertices(CaveGenerator.GenerateWallShapes(cells, level), color); #endif } From 0abdcb969ded4a15ead0d26e14b085501b6b670f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 15:18:46 +0300 Subject: [PATCH 26/29] Fixed "failed to write event" errors when a client or server tries to change an enum value of an item (e.g. the output type of an oscillator component) --- .../BarotraumaShared/Source/Items/Item.cs | 22 +++++++++++++++++++ .../Serialization/SerializableProperty.cs | 1 + 2 files changed, 23 insertions(+) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 5fe179479..4e3d6f8e4 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1430,6 +1430,10 @@ namespace Barotrauma msg.Write(((Rectangle)value).Width); msg.Write(((Rectangle)value).Height); } + else if (value is Enum) + { + msg.Write((int)value); + } else { throw new System.NotImplementedException("Serializing item properties of the type \"" + value.GetType() + "\" not supported"); @@ -1487,6 +1491,24 @@ namespace Barotrauma { property.TrySetValue(new Vector4(msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32(), msg.ReadInt32())); } + else if (typeof(Enum).IsAssignableFrom(type)) + { + int intVal = msg.ReadInt32(); + try + { + property.TrySetValue(Enum.ToObject(type, intVal)); + } + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("Failed to convert the int value \"" + intVal + "\" to " + type, e); +#endif + GameAnalyticsManager.AddErrorEventOnce( + "Item.ReadPropertyChange:" + Name + ":" + type, + GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, + "Failed to convert the int value \"" + intVal + "\" to " + type + " (item " + Name + ")"); + } + } else { return; diff --git a/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs b/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs index 6ab463699..7e1d34860 100644 --- a/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs +++ b/Barotrauma/BarotraumaShared/Source/Serialization/SerializableProperty.cs @@ -223,6 +223,7 @@ namespace Barotrauma return false; } propertyInfo.SetValue(obj, enumVal); + return true; } else { From f0a663bab0d63afa6ffceffca76e8cf0ef16e991 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 16:10:49 +0300 Subject: [PATCH 27/29] Added some extra information to OpenAL error messages --- .../Source/Sounds/OggSound.cs | 12 ++-- .../Source/Sounds/OggStream.cs | 58 +++++++++++-------- .../BarotraumaClient/Source/Sounds/Sound.cs | 6 +- .../Source/Sounds/SoundManager.cs | 20 +++---- 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs index 37aa0a313..172ce99b2 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs @@ -56,7 +56,7 @@ namespace Barotrauma.Sounds AL.BufferData(sound.alBufferId, reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, sound.castBuffer, readSamples * sizeof(short), reader.SampleRate); - ALHelper.Check(); + ALHelper.Check(oggFile); } //AL.Source(alSourceId, ALSourcei.Buffer, alBufferId); @@ -100,12 +100,12 @@ namespace Barotrauma.Sounds public void Dispose() { - //var state = AL.GetSourceState(alSourceId); - //if (state == ALSourceState.Playing || state == ALSourceState.Paused) - // Stop(); System.Diagnostics.Debug.WriteLine(alBufferId); - //AL.DeleteSource(alSourceId); - AL.DeleteBuffer(alBufferId); + if (alBufferId > 0) + { + AL.DeleteBuffer(alBufferId); + alBufferId = 0; + } //if (ALHelper.Efx.IsInitialized) // ALHelper.Efx.DeleteFilter(alFilterId); diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs index 6f761edd3..945cd0173 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OggStream.cs @@ -45,20 +45,24 @@ namespace Barotrauma.Sounds //logHandler(String.Format("Total memory : {0:0.###} {1} ", usedHeap, sizes[order]), 0, 6); } - public static void Check() + public static void Check(string extraErrorMsg = "") { ALError error; if ((error = AL.GetError()) != ALError.NoError) { + string errorMsg = "OpenAL error: " + AL.GetErrorString(error); + if (!string.IsNullOrEmpty(extraErrorMsg)) errorMsg += " {" + extraErrorMsg + "} "; + errorMsg += "\n" + Environment.StackTrace; + #if DEBUG - DebugConsole.ThrowError("OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace); + DebugConsole.ThrowError(errorMsg); #else - DebugConsole.NewMessage("OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace, Microsoft.Xna.Framework.Color.Red); + DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red); #endif GameAnalyticsManager.AddErrorEventOnce( - "OggStream.Check:"+ AL.GetErrorString(error), + "OggStream.Check:" + AL.GetErrorString(error) + extraErrorMsg, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, - "OpenAL error: " + AL.GetErrorString(error) + "\n" + Environment.StackTrace); + errorMsg); } } } @@ -87,9 +91,17 @@ namespace Barotrauma.Sounds public Action LogHandler; #endif - public OggStream(string filename, int bufferCount = DefaultBufferCount) : this(File.OpenRead(filename), bufferCount) { } - public OggStream(Stream stream, int bufferCount = DefaultBufferCount) + public string FileName { + get; + private set; + } + + public OggStream(string filename, int bufferCount = DefaultBufferCount) : this(File.OpenRead(filename), filename, bufferCount) { } + public OggStream(Stream stream, string fileName, int bufferCount = DefaultBufferCount) + { + this.FileName = fileName; + BufferCount = bufferCount; alBufferIds = AL.GenBuffers(bufferCount); @@ -98,7 +110,7 @@ namespace Barotrauma.Sounds if (ALHelper.XRam.IsInitialized) { ALHelper.XRam.SetBufferMode(BufferCount, ref alBufferIds[0], XRamExtension.XRamStorage.Hardware); - ALHelper.Check(); + ALHelper.Check(fileName); } if (ALHelper.Efx.IsInitialized) @@ -167,7 +179,7 @@ namespace Barotrauma.Sounds AL.SourcePlay(alSourceId); this.Volume = volume; - ALHelper.Check(); + ALHelper.Check(FileName); Preparing = false; @@ -181,7 +193,7 @@ namespace Barotrauma.Sounds OggStreamer.Instance.RemoveStream(this); AL.SourcePause(alSourceId); - ALHelper.Check(); + ALHelper.Check(FileName); } public void Resume() @@ -191,7 +203,7 @@ namespace Barotrauma.Sounds OggStreamer.Instance.AddStream(this); AL.SourcePlay(alSourceId); - ALHelper.Check(); + ALHelper.Check(FileName); } public void Stop() @@ -230,7 +242,7 @@ namespace Barotrauma.Sounds set { AL.Source(alSourceId, ALSourcef.Gain, volume = value); - ALHelper.Check(); + ALHelper.Check(FileName); } } @@ -260,20 +272,20 @@ namespace Barotrauma.Sounds /*if (ALHelper.Efx.IsInitialized) ALHelper.Efx.DeleteFilter(alFilterId);*/ - ALHelper.Check(); + ALHelper.Check(FileName); } void StopPlayback() { AL.SourceStop(alSourceId); - ALHelper.Check(); + ALHelper.Check(FileName); } void Empty() { int queued; AL.GetSource(alSourceId, ALGetSourcei.BuffersQueued, out queued); - ALHelper.Check(); + ALHelper.Check(FileName); if (queued > 0) { @@ -296,12 +308,12 @@ namespace Barotrauma.Sounds if (processed > 0) { AL.SourceUnqueueBuffers(alSourceId, processed, salvaged); - ALHelper.Check(); + ALHelper.Check(FileName); } // Try turning it off again? AL.SourceStop(alSourceId); - ALHelper.Check(); + ALHelper.Check(FileName); Empty(); } @@ -318,7 +330,7 @@ namespace Barotrauma.Sounds // Fill first buffer synchronously OggStreamer.Instance.FillBuffer(this, alBufferIds[0]); AL.SourceQueueBuffer(alSourceId, alBufferIds[0]); - ALHelper.Check(); + ALHelper.Check(FileName); // Schedule the others asynchronously OggStreamer.Instance.AddStream(this); @@ -433,7 +445,7 @@ namespace Barotrauma.Sounds } AL.BufferData(bufferId, stream.Reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer, readSamples * sizeof(short), stream.Reader.SampleRate); - ALHelper.Check(); + ALHelper.Check(stream.FileName); return readSamples != BufferSize; } @@ -470,10 +482,10 @@ namespace Barotrauma.Sounds int queued; AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersQueued, out queued); - ALHelper.Check(); + ALHelper.Check(stream.FileName); int processed; AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersProcessed, out processed); - ALHelper.Check(); + ALHelper.Check(stream.FileName); if (processed == 0 && queued == stream.BufferCount) continue; @@ -500,7 +512,7 @@ namespace Barotrauma.Sounds } AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers); - ALHelper.Check(); + ALHelper.Check(stream.FileName); if (finished && !stream.IsLooped) continue; @@ -518,7 +530,7 @@ namespace Barotrauma.Sounds if (state == ALSourceState.Stopped) { AL.SourcePlay(stream.alSourceId); - ALHelper.Check(); + ALHelper.Check(stream.FileName); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs index c1dd80996..db4563b2e 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs @@ -54,7 +54,7 @@ namespace Barotrauma { DebugConsole.ThrowError("Failed to load sound "+file+"!", e); } - ALHelper.Check(); + ALHelper.Check(file); } baseVolume = 1.0f; @@ -219,7 +219,7 @@ namespace Barotrauma (SoundManager.IsPlaying(alSourceId) || SoundManager.IsPaused(alSourceId))) { SoundManager.Stop(alSourceId); - ALHelper.Check(); + ALHelper.Check(filePath); } foreach (Sound s in loadedSounds) @@ -228,7 +228,7 @@ namespace Barotrauma } SoundManager.ClearAlSource(AlBufferId); - ALHelper.Check(); + ALHelper.Check(filePath); if (oggSound != null) { diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs b/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs index 301583f3c..cd1b4db7a 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs @@ -143,7 +143,7 @@ namespace Barotrauma.Sounds volume = 0.0f; } - if (sourceIndex<1 || soundsPlaying[sourceIndex] != sound) + if (sourceIndex < 1 || soundsPlaying[sourceIndex] != sound) { sourceIndex = Play(sound, position, volume, 0.0f, true); } @@ -153,7 +153,7 @@ namespace Barotrauma.Sounds AL.Source(alSources[sourceIndex], ALSourceb.Looping, true); } - ALHelper.Check(); + ALHelper.Check(sound?.FilePath); return sourceIndex; } @@ -165,7 +165,7 @@ namespace Barotrauma.Sounds return; AL.SourcePause(alSources[sourceIndex]); - ALHelper.Check(); + ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath); } public static void Resume(int sourceIndex) @@ -176,7 +176,7 @@ namespace Barotrauma.Sounds return; AL.SourcePlay(alSources[sourceIndex]); - ALHelper.Check(); + ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath); } public static void Stop(int sourceIndex) @@ -291,7 +291,7 @@ namespace Barotrauma.Sounds ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = value); ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId); - ALHelper.Check(); + ALHelper.Check(soundsPlaying[i]?.FilePath); } } } @@ -316,7 +316,7 @@ namespace Barotrauma.Sounds ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassGain); ALHelper.Efx.BindFilterToSource(alSources[sourceIndex], lowpassFilterId); - ALHelper.Check(); + ALHelper.Check(soundsPlaying[sourceIndex]?.FilePath); } public static OggStream StartStream(string file, float volume = 1.0f) @@ -331,7 +331,7 @@ namespace Barotrauma.Sounds oggStream.Play(volume); - ALHelper.Check(); + ALHelper.Check(file); return oggStream; } @@ -361,15 +361,15 @@ namespace Barotrauma.Sounds for (int i = 0; i < DefaultSourceCount; i++) { + string soundPath = soundsPlaying[i]?.FilePath; var state = OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]); if (state == OpenTK.Audio.OpenAL.ALSourceState.Playing || state == OpenTK.Audio.OpenAL.ALSourceState.Paused) { Stop(i); } - OpenTK.Audio.OpenAL.AL.DeleteSource(alSources[i]); - - ALHelper.Check(); + OpenTK.Audio.OpenAL.AL.DeleteSource(alSources[i]); + ALHelper.Check(soundPath); } if (oggStream != null) From faf0a87cfa562499d7dd72b3c1c50a08fd768142 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 16:33:12 +0300 Subject: [PATCH 28/29] Added a bunch of error checks to physicsbody-manipulating code --- .../Source/Characters/Animation/Ragdoll.cs | 6 +- .../Source/Items/Components/DockingPort.cs | 20 ++++- .../Source/Items/Components/Door.cs | 9 ++ .../Source/Physics/PhysicsBody.cs | 84 ++++++++++++++++--- 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs index 3456f0ccf..7d55f8c61 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs @@ -368,8 +368,8 @@ namespace Barotrauma foreach (var joint in LimbJoints) { - joint.BodyB.SetTransform( - joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB)*0.1f, + joint.LimbB?.body?.SetTransform( + joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB) * 0.1f, (joint.LowerLimit + joint.UpperLimit) / 2.0f); } @@ -394,7 +394,7 @@ namespace Barotrauma Limb torso = GetLimb(LimbType.Torso); Limb head = GetLimb(LimbType.Head); - MainLimb = torso == null ? head : torso; + MainLimb = torso ?? head; } public void AddJoint(XElement subElement, float scale = 1.0f) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs index 236a2c85d..63108d2ea 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs @@ -345,17 +345,31 @@ namespace Barotrauma.Items.Components private void CreateDoorBody() { + Vector2 position = ConvertUnits.ToSimUnits(item.Position + (dockingTarget.door.Item.WorldPosition - item.WorldPosition)); + if (!MathUtils.IsValid(position)) + { + string errorMsg = + "Attempted to create a door body at an invalid position (item pos: " + item.Position + + ", item world pos: " + item.WorldPosition + + ", docking target world pos: " + DockingTarget.door.Item.WorldPosition + ")\n" + Environment.StackTrace; + + DebugConsole.ThrowError(errorMsg); + GameAnalyticsManager.AddErrorEventOnce( + "DockingPort.CreateDoorBody:InvalidPosition", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + errorMsg); + position = Vector2.Zero; + } + doorBody = BodyFactory.CreateRectangle(GameMain.World, dockingTarget.door.Body.width, dockingTarget.door.Body.height, 1.0f, + position, dockingTarget.door); doorBody.CollisionCategories = Physics.CollisionWall; doorBody.BodyType = BodyType.Static; - doorBody.SetTransform( - ConvertUnits.ToSimUnits(item.Position + (dockingTarget.door.Item.WorldPosition - item.WorldPosition)), - 0.0f); } private void CreateHull() diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs index b3c8a5b03..c86ce633a 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs @@ -386,6 +386,15 @@ namespace Barotrauma.Items.Components foreach (PhysicsBody body in bodies) { float diff = 0.0f; + if (!MathUtils.IsValid(body.SimPosition)) + { + DebugConsole.ThrowError("Failed to push a limb out of a doorway - position of the body (character \"" + c.Name + "\") is not valid (" + body.SimPosition + ")"); + GameAnalyticsManager.AddErrorEventOnce("PushCharactersAway:LimbPosInvalid", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + "Failed to push a character out of a doorway - position of the character \"" + c.Name + "\" is not valid (" + body.SimPosition + ")." + + " Removed: " + c.Removed + + " Remoteplayer: " + c.IsRemotePlayer); + continue; + } if (isHorizontal) { diff --git a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs index 7ce46113a..4972e4f70 100644 --- a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs @@ -360,6 +360,44 @@ namespace Barotrauma this.radius = radius; } + private bool IsValidValue(float value, string valueName) + { + if (!MathUtils.IsValid(value)) + { + string errorMsg = + "Attempted to apply invalid " + valueName + + " to a physics body (userdata: " + UserData == null ? "null" : UserData.ToString() + + "), value: " + value + "\n" + Environment.StackTrace; + + DebugConsole.ThrowError(errorMsg); + GameAnalyticsManager.AddErrorEventOnce( + "PhysicsBody.SetPosition:InvalidPosition", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + errorMsg); + return false; + } + return true; + } + + private bool IsValidValue(Vector2 value, string valueName) + { + if (!MathUtils.IsValid(value)) + { + string errorMsg = + "Attempted to apply invalid " + valueName + + " to a physics body (userdata: " + UserData == null ? "null" : UserData.ToString() + + "), value: " + value + "\n" + Environment.StackTrace; + + DebugConsole.ThrowError(errorMsg); + GameAnalyticsManager.AddErrorEventOnce( + "PhysicsBody.SetPosition:InvalidPosition", + GameAnalyticsSDK.Net.EGAErrorSeverity.Error, + errorMsg); + return false; + } + return true; + } + public void ResetDynamics() { body.ResetDynamics(); @@ -367,6 +405,7 @@ namespace Barotrauma public void ApplyLinearImpulse(Vector2 impulse) { + if (!IsValidValue(impulse, "impulse")) return; body.ApplyLinearImpulse(impulse); } @@ -375,6 +414,9 @@ namespace Barotrauma /// public void ApplyLinearImpulse(Vector2 impulse, float maxVelocity) { + if (!IsValidValue(impulse, "impulse")) return; + if (!IsValidValue(maxVelocity, "max velocity")) return; + float currSpeed = body.LinearVelocity.Length(); Vector2 velocityAddition = impulse / Mass; Vector2 newVelocity = body.LinearVelocity + velocityAddition; @@ -385,21 +427,26 @@ namespace Barotrauma public void ApplyLinearImpulse(Vector2 impulse, Vector2 point) { + if (!IsValidValue(impulse, "impulse")) return; body.ApplyLinearImpulse(impulse, point); } public void ApplyForce(Vector2 force) { + if (!IsValidValue(force, "force")) return; body.ApplyForce(force); } public void ApplyForce(Vector2 force, Vector2 point) { + if (!IsValidValue(force, "force")) return; + if (!IsValidValue(point, "point")) return; body.ApplyForce(force, point); } public void ApplyTorque(float torque) { + if (!IsValidValue(torque, "torque")) return; body.ApplyTorque(torque); } @@ -408,7 +455,10 @@ namespace Barotrauma System.Diagnostics.Debug.Assert(MathUtils.IsValid(simPosition)); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); - + + if (!IsValidValue(simPosition, "position")) return; + if (!IsValidValue(rotation, "rotation")) return; + body.SetTransform(simPosition, rotation); SetPrevTransform(simPosition, rotation); } @@ -418,14 +468,20 @@ namespace Barotrauma System.Diagnostics.Debug.Assert(MathUtils.IsValid(simPosition)); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f); System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f); - + + if (!IsValidValue(simPosition, "position")) return; + if (!IsValidValue(rotation, "rotation")) return; + body.SetTransformIgnoreContacts(ref simPosition, rotation); SetPrevTransform(simPosition, rotation); } - public void SetPrevTransform(Vector2 position, float rotation) + public void SetPrevTransform(Vector2 simPosition, float rotation) { - prevPosition = position; + if (!IsValidValue(simPosition, "position")) return; + if (!IsValidValue(rotation, "rotation")) return; + + prevPosition = simPosition; prevRotation = rotation; } @@ -440,16 +496,19 @@ namespace Barotrauma prevPosition = (Vector2)targetPosition; } - body.SetTransform((Vector2)targetPosition, targetRotation == null ? body.Rotation : (float)targetRotation); + SetTransform((Vector2)targetPosition, targetRotation == null ? body.Rotation : (float)targetRotation); targetPosition = null; } - public void MoveToPos(Vector2 pos, float force, Vector2? pullPos = null) + public void MoveToPos(Vector2 simPosition, float force, Vector2? pullPos = null) { if (pullPos == null) pullPos = body.Position; + if (!IsValidValue(simPosition, "position")) return; + if (!IsValidValue(force, "force")) return; + Vector2 vel = body.LinearVelocity; - Vector2 deltaPos = pos - (Vector2)pullPos; + Vector2 deltaPos = simPosition - (Vector2)pullPos; deltaPos *= force; body.ApplyLinearImpulse((deltaPos - vel * 0.5f) * body.Mass, (Vector2)pullPos); } @@ -474,8 +533,8 @@ namespace Barotrauma dragForce = Math.Min(drag, Mass * 500.0f) * -velDir; } - body.ApplyForce(dragForce + buoyancy); - body.ApplyTorque(body.AngularVelocity * body.Mass * -0.08f); + ApplyForce(dragForce + buoyancy); + ApplyTorque(body.AngularVelocity * body.Mass * -0.08f); } @@ -559,18 +618,17 @@ namespace Barotrauma public void SmoothRotate(float targetRotation, float force = 10.0f) { float nextAngle = body.Rotation + body.AngularVelocity * (float)Timing.Step; - float angle = MathUtils.GetShortestAngle(nextAngle, targetRotation); - - float torque = angle * 60.0f * (force/100.0f); + float torque = angle * 60.0f * (force / 100.0f); if (body.IsKinematic) { + if (!IsValidValue(torque, "torque")) return; body.AngularVelocity = torque; } else { - body.ApplyTorque(body.Mass * torque); + ApplyTorque(body.Mass * torque); } } From 9880a74218edd2699f7bb3dc5487514dee4d81cf Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 20 Jul 2018 16:37:41 +0300 Subject: [PATCH 29/29] Added check for removed AITarget to EnemyAIController.UpdateEscape --- .../Source/Characters/AI/EnemyAIController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 495add3f1..72b956137 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -274,6 +274,12 @@ namespace Barotrauma private void UpdateEscape(float deltaTime) { + if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed) + { + state = AIState.None; + return; + } + SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5); SteeringManager.SteeringWander(1.0f); SteeringManager.SteeringAvoid(deltaTime, 2f);