diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems index 96e169d05..26cd574b9 100644 --- a/Barotrauma/BarotraumaClient/ClientCode.projitems +++ b/Barotrauma/BarotraumaClient/ClientCode.projitems @@ -202,6 +202,8 @@ + + @@ -220,7 +222,6 @@ - Never diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index c96a76c05..a96474014 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -118,9 +118,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -350,7 +347,7 @@ - + @@ -368,8 +365,9 @@ - + - + + \ No newline at end of file diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index b57d6b7cc..82c7835d0 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -117,9 +117,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/Barotrauma/BarotraumaClient/OpenAL32.dll b/Barotrauma/BarotraumaClient/OpenAL32.dll deleted file mode 100644 index f903a0c63..000000000 Binary files a/Barotrauma/BarotraumaClient/OpenAL32.dll and /dev/null differ diff --git a/Barotrauma/BarotraumaClient/OpenTK.dll.config b/Barotrauma/BarotraumaClient/OpenTK.dll.config deleted file mode 100644 index 140d56665..000000000 --- a/Barotrauma/BarotraumaClient/OpenTK.dll.config +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs index 318d1d048..73c1c27ad 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/AI/AITarget.cs @@ -39,10 +39,14 @@ namespace Barotrauma else if (Entity is Item) { color = Color.CadetBlue; + // disable the indicators for items, because they clutter the debug view + return; } else { color = Color.WhiteSmoke; + // disable the indicators for structures, because they clutter the debug view + return; } ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom); ShapeExtensions.DrawCircle(spriteBatch, pos, 6, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index 2e11c7af2..aae0a57f9 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -219,7 +219,7 @@ namespace Barotrauma { //hull subs don't match => teleport the camera to the other sub character.Submarine = serverHull.Submarine; - character.CurrentHull = currentHull = serverHull; + character.CurrentHull = CurrentHull = serverHull; SetPosition(serverPos.Position); character.MemLocalState.Clear(); } @@ -369,11 +369,11 @@ namespace Barotrauma LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime)); foreach (var deformation in SpriteDeformations) { + if (character.IsDead && deformation.DeformationParams.StopWhenHostIsDead) { continue; } if (deformation.DeformationParams.UseMovementSine) { if (this is AnimController animator) { - //deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos + MathHelper.Pi); deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.DeformationParams.Frequency + MathHelper.Pi * deformation.DeformationParams.SineOffset); } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs index 63beecb56..a3d57f795 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs @@ -538,13 +538,10 @@ namespace Barotrauma if (wearable.InheritLimbDepth) { depth = ActiveSprite.Depth - depthStep; - if (wearable.DepthLimb != LimbType.None) + Limb depthLimb = (wearable.DepthLimb == LimbType.None) ? this : character.AnimController.GetLimb(wearable.DepthLimb); + if (depthLimb != null) { - Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb); - if (depthLimb != null) - { - depth = depthLimb.ActiveSprite.Depth - depthStep; - } + depth = depthLimb.ActiveSprite.Depth - depthStep; } } var wearableItemComponent = wearable.WearableComponent; diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index f8a34fd0f..e2ba2d983 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -62,9 +62,21 @@ namespace Barotrauma { frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.45f), GUI.Canvas) { MinSize = new Point(400, 300), AbsoluteOffset = new Point(10, 10) }, color: new Color(0.4f, 0.4f, 0.4f, 0.8f)); + var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), frame.RectTransform, Anchor.Center), style: null); - listBox = new GUIListBox(new RectTransform(new Point(paddedFrame.Rect.Width, paddedFrame.Rect.Height - 30), paddedFrame.RectTransform) + var toggleText = new GUITextBlock(new RectTransform(new Point(paddedFrame.Rect.Width-30, 20), paddedFrame.RectTransform, Anchor.TopLeft), TextManager.Get("DebugConsoleHelpText"), new Color(150,150,200,255), GUI.SmallFont, Alignment.CenterLeft, style: null); + + var closeButton = new GUIButton(new RectTransform(new Point(20, 20), paddedFrame.RectTransform, Anchor.TopRight), "X", color: Color.Red); + closeButton.OnClicked += (btn, userdata) => + { + isOpen = false; + GUI.ForceMouseOn(null); + textBox.Deselect(); + return true; + }; + + listBox = new GUIListBox(new RectTransform(new Point(paddedFrame.Rect.Width, paddedFrame.Rect.Height - 50), paddedFrame.RectTransform, Anchor.Center) { IsFixedSize = false }, color: Color.Black * 0.9f); @@ -80,9 +92,6 @@ namespace Barotrauma ResetAutoComplete(); } }; - - NewMessage("Press F3 to open/close the debug console", Color.Cyan); - NewMessage("Enter \"help\" for a list of available console commands", Color.Cyan); } public static void AddToGUIUpdateList() @@ -130,6 +139,12 @@ namespace Barotrauma textBox.Deselect(); } } + else if (isOpen && PlayerInput.KeyHit(Keys.Escape)) + { + isOpen = false; + GUI.ForceMouseOn(null); + textBox.Deselect(); + } if (isOpen) { diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index be2740daa..f81002868 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -230,11 +230,18 @@ namespace Barotrauma if (GameMain.ShowPerf) { int y = 10; - DrawString(spriteBatch, new Vector2(300, y), "Draw - Max val: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue()+" ms", Color.Green, Color.Black * 0.8f, font: GUI.SmallFont); + DrawString(spriteBatch, new Vector2(300, y), + "Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" + + " Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms", + Color.Green, Color.Black * 0.8f, font: SmallFont); y += 15; GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.Green); y += 50; - DrawString(spriteBatch, new Vector2(300, y), "Update - Max val: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue() + " ms", Color.LightBlue, Color.Black * 0.8f, font: GUI.SmallFont); + + DrawString(spriteBatch, new Vector2(300, y), + "Update - Avg: " + GameMain.PerformanceCounter.UpdateTimeGraph.Average().ToString("0.00") + " ms" + + " Max: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue().ToString("0.00") + " ms", + Color.LightBlue, Color.Black * 0.8f, font: SmallFont); y += 15; GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.LightBlue); GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), 20, 0, Color.Red); @@ -243,7 +250,7 @@ namespace Barotrauma { float elapsedMillisecs = GameMain.PerformanceCounter.GetAverageElapsedMillisecs(key); DrawString(spriteBatch, new Vector2(300, y), - key + ": " + elapsedMillisecs, + key + ": " + elapsedMillisecs.ToString("0.00"), Color.Lerp(Color.LightGreen, Color.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, SmallFont); y += 15; diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUILayoutGroup.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUILayoutGroup.cs index 18cbe23c7..e797b022a 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUILayoutGroup.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUILayoutGroup.cs @@ -85,7 +85,9 @@ namespace Barotrauma { float totalSize = RectTransform.Children .Where(c => !c.GUIComponent.IgnoreLayoutGroups) - .Sum(c => isHorizontal ? c.Rect.Width : c.Rect.Height); + .Sum(c => isHorizontal ? + MathHelper.Clamp(c.Rect.Width, c.MinSize.X, c.MaxSize.X) : + MathHelper.Clamp(c.Rect.Height, c.MinSize.Y, c.MaxSize.Y)); totalSize += (RectTransform.Children.Count() - 1) * diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs index 9ee247a23..2d631d19d 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs @@ -117,7 +117,9 @@ namespace Barotrauma { LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true) { Stretch = true }; - TextBox = new GUITextBox(new RectTransform(Vector2.One, LayoutGroup.RectTransform), textAlignment: textAlignment, style: style) + float relativeButtonAreaWidth = MathHelper.Clamp(Rect.Height / (float)Rect.Width, 0.1f, 0.5f); + + TextBox = new GUITextBox(new RectTransform(new Vector2(1.0f - relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform), textAlignment: textAlignment, style: style) { ClampText = false, // For some reason the caret in the number inputs is dimmer than it should. @@ -126,7 +128,7 @@ namespace Barotrauma CaretColor = Color.White }; TextBox.OnTextChanged += TextChanged; - var buttonArea = new GUIFrame(new RectTransform(new Vector2(0.02f, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight) { MinSize = new Point(Rect.Height, 0) }, style: null); + var buttonArea = new GUIFrame(new RectTransform(new Vector2(relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight) { MinSize = new Point(Rect.Height, 0) }, style: null); PlusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), "+"); PlusButton.OnButtonDown += () => { @@ -201,6 +203,8 @@ namespace Barotrauma TextBox.textFilterFunction = text => new string(text.Where(c => char.IsDigit(c) || c == '.' || c == '-').ToArray()); break; } + + LayoutGroup.Recalculate(); } private void ReduceValue() diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs index e93f22c76..780264181 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs @@ -35,8 +35,6 @@ namespace Barotrauma this.graphicsDevice = graphicsDevice; componentStyles = new Dictionary(); - GameMain.Instance.OnResolutionChanged += () => { RescaleFonts(); }; - XDocument doc; try { @@ -89,6 +87,8 @@ namespace Barotrauma break; } } + + GameMain.Instance.OnResolutionChanged += () => { RescaleFonts(); }; } /// diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs index 5192c5a0f..8692bf140 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBlock.cs @@ -20,6 +20,7 @@ namespace Barotrauma protected Color textColor; private string wrappedText; + private string censoredText; public delegate string TextGetterHandler(); public TextGetterHandler TextGetter; @@ -175,6 +176,17 @@ namespace Barotrauma SetTextPos(); } } + + public bool Censor + { + get; + set; + } + + public string CensoredText + { + get { return censoredText; } + } /// /// This is the new constructor. @@ -204,6 +216,8 @@ namespace Barotrauma RectTransform.ScaleChanged += SetTextPos; RectTransform.SizeChanged += SetTextPos; + + Censor = false; } public void CalculateHeightFromText() @@ -225,13 +239,19 @@ namespace Barotrauma { if (text == null) return; + censoredText = ""; + for (int i=0;i 0) { wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale); @@ -338,7 +358,7 @@ namespace Barotrauma } Font.DrawString(spriteBatch, - Wrap ? wrappedText : text, + Censor ? censoredText : (Wrap ? wrappedText : text), pos, textColor * (textColor.A / 255.0f), 0.0f, origin, TextScale, diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs index 886e5aa2c..94ace0ef1 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs @@ -142,6 +142,12 @@ namespace Barotrauma } } + public bool Censor + { + get { return textBlock.Censor; } + set { textBlock.Censor = value; } + } + public override string ToolTip { get @@ -253,9 +259,12 @@ namespace Barotrauma textBlock.Text = textBlock.Text.Substring(0, (int)maxTextLength); } } - else if (ClampText && Font.MeasureString(textBlock.Text).X > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z)) + else { - textBlock.Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1); + while (ClampText && textBlock.Text.Length>0 && Font.MeasureString(textBlock.Text).X > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z)) + { + textBlock.Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1); + } } } if (store) @@ -267,9 +276,10 @@ namespace Barotrauma private void CalculateCaretPos() { - if (textBlock.WrappedText.Contains("\n")) + string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText; + if (textDrawn.Contains("\n")) { - string[] lines = textBlock.WrappedText.Split('\n'); + string[] lines = textDrawn.Split('\n'); int totalIndex = 0; for (int i = 0; i < lines.Length; i++) { @@ -282,7 +292,7 @@ namespace Barotrauma int index = currentLineLength - diff; Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index)); Vector2 lastLineSize = Font.MeasureString(lines[i]); - float totalTextHeight = Font.MeasureString(textBlock.WrappedText.Substring(0, totalIndex)).Y; + float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y; caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin; break; } @@ -290,7 +300,8 @@ namespace Barotrauma } else { - Vector2 textSize = Font.MeasureString(textBlock.Text.Substring(0, CaretIndex)); + textDrawn = Censor ? textBlock.CensoredText : textBlock.Text; + Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex)); caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin; } caretPosDirty = false; @@ -298,17 +309,18 @@ namespace Barotrauma protected List> GetAllPositions() { + string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText; var positions = new List>(); - if (textBlock.WrappedText.Contains("\n")) + if (textDrawn.Contains("\n")) { - string[] lines = textBlock.WrappedText.Split('\n'); + string[] lines = textDrawn.Split('\n'); int index = 0; int totalIndex = 0; for (int i = 0; i < lines.Length; i++) { string line = lines[i]; totalIndex += line.Length; - float totalTextHeight = Font.MeasureString(textBlock.WrappedText.Substring(0, totalIndex)).Y; + float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y; for (int j = 0; j <= line.Length; j++) { Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j)); @@ -321,9 +333,10 @@ namespace Barotrauma } else { + textDrawn = Censor ? textBlock.CensoredText : textBlock.Text; for (int i = 0; i <= textBlock.Text.Length; i++) { - Vector2 textSize = Font.MeasureString(textBlock.Text.Substring(0, i)); + Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i)); Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y) + textBlock.TextPos - textBlock.Origin; //DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke); positions.Add(new Tuple(textBlock.Rect.Location.ToVector2() + indexPos, i)); @@ -822,6 +835,7 @@ namespace Barotrauma private void CalculateSelection() { + string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText; InitSelectionStart(); selectionEndIndex = CaretIndex; selectionEndPos = caretPos; @@ -829,12 +843,12 @@ namespace Barotrauma if (IsLeftToRight) { selectedText = Text.Substring(selectionStartIndex, selectedCharacters); - selectionRectSize = Font.MeasureString(textBlock.WrappedText.Substring(selectionStartIndex, selectedCharacters)); + selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionStartIndex, selectedCharacters)); } else { selectedText = Text.Substring(selectionEndIndex, selectedCharacters); - selectionRectSize = Font.MeasureString(textBlock.WrappedText.Substring(selectionEndIndex, selectedCharacters)); + selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionEndIndex, selectedCharacters)); } } } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/RectTransform.cs b/Barotrauma/BarotraumaClient/Source/GUI/RectTransform.cs index 365a9a2a9..b2eca2968 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/RectTransform.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/RectTransform.cs @@ -21,6 +21,11 @@ namespace Barotrauma BottomLeft, BottomCenter, BottomRight } + public enum ScaleBasis + { + Normal, BothWidth, BothHeight + } + public class RectTransform { #region Fields and Properties @@ -286,6 +291,8 @@ namespace Barotrauma } } + private ScaleBasis scaleBasis; + public bool IsLastChild { get @@ -320,9 +327,10 @@ namespace Barotrauma #endregion #region Initialization - public RectTransform(Vector2 relativeSize, RectTransform parent, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null) + public RectTransform(Vector2 relativeSize, RectTransform parent, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null, ScaleBasis scaleBasis = ScaleBasis.Normal) { Init(parent, anchor, pivot); + this.scaleBasis = scaleBasis; this.relativeSize = relativeSize; this.minSize = minSize; this.maxSize = maxSize; @@ -340,6 +348,7 @@ namespace Barotrauma public RectTransform(Point absoluteSize, RectTransform parent = null, Anchor anchor = Anchor.TopLeft, Pivot? pivot = null) { Init(parent, anchor, pivot); + this.scaleBasis = ScaleBasis.Normal; this.nonScaledSize = absoluteSize; RecalculateScale(); RecalculateRelativeSize(); @@ -416,7 +425,16 @@ namespace Barotrauma protected void RecalculateAbsoluteSize() { - nonScaledSize = NonScaledParentRect.Size.Multiply(RelativeSize).Clamp(MinSize, MaxSize); + Point size = NonScaledParentRect.Size; + if (scaleBasis == ScaleBasis.BothWidth) + { + size.Y = size.X; + } + else if (scaleBasis == ScaleBasis.BothHeight) + { + size.X = size.Y; + } + nonScaledSize = size.Multiply(RelativeSize).Clamp(MinSize, MaxSize); recalculateRect = true; SizeChanged?.Invoke(); } diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 6f1f43694..c87ff6bb1 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -159,14 +159,7 @@ namespace Barotrauma public GameMain() { -/*#if !DEBUG && OSX - // Use a separate path for content that's editable due to macOS's .app bundles crashing when edited during runtime - string macPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library/Barotrauma"); - Directory.SetCurrentDirectory(macPath); - Content.RootDirectory = macPath + "/Content"; -#else*/ Content.RootDirectory = "Content"; -/*#endif*/ GraphicsDeviceManager = new GraphicsDeviceManager(this); @@ -280,7 +273,7 @@ namespace Barotrauma canLoadInSeparateThread = true; #endif - loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "", canLoadInSeparateThread); + loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "Load", canLoadInSeparateThread); } private void InitUserStats() @@ -541,7 +534,9 @@ namespace Barotrauma /// protected override void UnloadContent() { + CoroutineManager.StopCoroutines("Load"); Video.Close(); + VoipCapture.Instance?.Dispose(); SoundManager?.Dispose(); } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs b/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs index e4e0bb2a6..ffcc67311 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/RoundSummary.cs @@ -114,7 +114,11 @@ namespace Barotrauma Character character = characterInfo.Character; if (character == null || character.IsDead) { - if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null) + if (characterInfo.CauseOfDeath == null) + { + statusText = TextManager.Get("CauseOfDeathDescription.Unknown"); + } + else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null) { string errorMsg = "Character \"" + character.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified)."; DebugConsole.ThrowError(errorMsg); @@ -126,7 +130,7 @@ namespace Barotrauma statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ? characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription : TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString()); - } + } statusColor = Color.DarkRed; } else diff --git a/Barotrauma/BarotraumaClient/Source/GameSettings.cs b/Barotrauma/BarotraumaClient/Source/GameSettings.cs index a19e7fce8..fa1794cd5 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSettings.cs @@ -3,7 +3,7 @@ using Barotrauma.Networking; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; -using OpenTK.Audio.OpenAL; +using OpenAL; using System; using System.Collections.Generic; using System.Diagnostics; @@ -75,6 +75,8 @@ namespace Barotrauma { settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center)); + Vector2 tickBoxScale = Vector2.One * 0.05f; + var settingsFramePadding = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.01f, IsHorizontal = true }; /// General tab -------------------------------------------------------------- @@ -96,7 +98,7 @@ namespace Barotrauma foreach (ContentPackage contentPackage in ContentPackage.List) { - var tickBox = new GUITickBox(new RectTransform(new Point(32, 32), contentPackageList.Content.RectTransform), contentPackage.Name) + var tickBox = new GUITickBox(new RectTransform(tickBoxScale, contentPackageList.Content.RectTransform, scaleBasis: ScaleBasis.BothHeight), contentPackage.Name) { UserData = contentPackage, OnSelected = SelectContentPackage, @@ -132,7 +134,7 @@ namespace Barotrauma if (newLanguage == Language) return true; Language = newLanguage; - ApplySettings(); + UnsavedSettings = true; var msgBox = new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage")); //change fonts to the default font of the new language to make sure @@ -250,7 +252,7 @@ namespace Barotrauma return true; }; - GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("EnableVSync")) + GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(tickBoxScale, leftColumn.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("EnableVSync")) { ToolTip = TextManager.Get("EnableVSyncToolTip"), OnSelected = (GUITickBox box) => @@ -266,7 +268,7 @@ namespace Barotrauma }; //TODO: remove hardcoded texts after the texts have been added to localization - GUITickBox pauseOnFocusLostBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), + GUITickBox pauseOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, leftColumn.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("PauseOnFocusLost", returnNull: true) ?? "Pause on focus lost"); pauseOnFocusLostBox.Selected = PauseOnFocusLost; pauseOnFocusLostBox.ToolTip = TextManager.Get("PauseOnFocusLostToolTip", returnNull: true) ?? "Pauses the game when its window is not in focus. Note that the game won't be paused when a multiplayer session is active."; @@ -331,7 +333,7 @@ namespace Barotrauma }; lightScrollBar.OnMoved(lightScrollBar, lightScrollBar.BarScroll); - new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("SpecularLighting")) + new GUITickBox(new RectTransform(tickBoxScale, rightColumn.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("SpecularLighting")) { ToolTip = TextManager.Get("SpecularLightingToolTip"), Selected = SpecularityEnabled, @@ -343,7 +345,7 @@ namespace Barotrauma } }; - new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("ChromaticAberration")) + new GUITickBox(new RectTransform(tickBoxScale, rightColumn.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("ChromaticAberration")) { ToolTip = TextManager.Get("ChromaticAberrationToolTip"), Selected = ChromaticAberrationEnabled, @@ -443,7 +445,7 @@ namespace Barotrauma }; voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll); - GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get("MuteOnFocusLost")); + GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost")); muteOnFocusLostBox.Selected = MuteOnFocusLost; muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip"); muteOnFocusLostBox.OnSelected = (tickBox) => @@ -455,13 +457,13 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChat")); - IList deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier); + IList deviceNames = Alc.GetStringList((IntPtr)null, Alc.CaptureDeviceSpecifier); foreach (string name in deviceNames) { DebugConsole.NewMessage(name + " " + name.Length.ToString(), Color.Lime); } - GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get("DirectionalVoiceChat")); + GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DirectionalVoiceChat")); directionalVoiceChat.Selected = UseDirectionalVoiceChat; directionalVoiceChat.ToolTip = TextManager.Get("DirectionalVoiceChatToolTip"); directionalVoiceChat.OnSelected = (tickBox) => @@ -470,14 +472,13 @@ namespace Barotrauma UnsavedSettings = true; return true; }; - - + if (string.IsNullOrWhiteSpace(VoiceCaptureDevice)) VoiceCaptureDevice = deviceNames[0]; #if (!OSX) - var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.EnsureUTF8(VoiceCaptureDevice), deviceNames.Count); + var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TrimAudioDeviceName(VoiceCaptureDevice), deviceNames.Count); foreach (string name in deviceNames) { - deviceList.AddItem(TextManager.EnsureUTF8(name), name); + deviceList.AddItem(TrimAudioDeviceName(name), name); } deviceList.OnSelected = (GUIComponent selected, object obj) => { @@ -488,28 +489,32 @@ namespace Barotrauma return true; }; #else - var suavemente = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), + var defaultDeviceGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), audioSliders.RectTransform), true, Anchor.CenterLeft); + var suavemente = new GUITextBlock(new RectTransform(new Vector2(.7f, 0.75f), null), TextManager.AddPunctuation(':', TextManager.Get("CurrentDevice"), TextManager.EnsureUTF8(VoiceCaptureDevice))) { ToolTip = TextManager.Get("CurrentDeviceToolTip.OSX"), - TextAlignment = Alignment.CenterX + TextAlignment = Alignment.CenterLeft }; - new GUIButton(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform), TextManager.Get("RefreshDefaultDevice")) + string refreshText = ToolBox.WrapText(TextManager.Get("RefreshDefaultDevice"), defaultDeviceGroup.RectTransform.Rect.Width * 0.3f, GUI.Font); + new GUIButton(new RectTransform(new Vector2(.3f, 0.75f), defaultDeviceGroup.RectTransform), refreshText) { ToolTip = TextManager.Get("RefreshDefaultDeviceToolTip"), OnClicked = (bt, userdata) => { - deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier); + deviceNames = Alc.GetStringList((IntPtr)null, Alc.CaptureDeviceSpecifier); if (VoiceCaptureDevice == deviceNames[0]) return true; VoipCapture.ChangeCaptureDevice(deviceNames[0]); - suavemente.Text = TextManager.AddPunctuation(':', TextManager.Get("CurrentDevice"), TextManager.EnsureUTF8(VoiceCaptureDevice)); + suavemente.Text = TextManager.AddPunctuation(':', TextManager.Get("CurrentDevice"), TrimAudioDeviceName(VoiceCaptureDevice)); suavemente.Flash(Color.Blue); return true; } }; + + suavemente.RectTransform.Parent = defaultDeviceGroup.RectTransform; #endif //var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.12f), audioSliders.RectTransform)); @@ -517,7 +522,7 @@ namespace Barotrauma for (int i = 0; i < 3; i++) { string langStr = "VoiceMode." + ((VoiceMode)i).ToString(); - var tick = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get(langStr)) + var tick = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get(langStr)) { ToolTip = TextManager.Get(langStr + "ToolTip") }; @@ -651,7 +656,7 @@ namespace Barotrauma }; aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll); - new GUITickBox(new RectTransform(new Point(32, 32), controlsLayoutGroup.RectTransform), TextManager.Get("EnableMouseLook")) + new GUITickBox(new RectTransform(tickBoxScale, controlsLayoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("EnableMouseLook")) { ToolTip = TextManager.Get("EnableMouseLookToolTip"), Selected = EnableMouseLook, @@ -776,6 +781,19 @@ namespace Barotrauma SelectTab(selectedTab); } + private string TrimAudioDeviceName(string name) + { + string[] prefixes = { "OpenAL Soft on " }; + foreach (string prefix in prefixes) + { + if (name.StartsWith(prefix, StringComparison.InvariantCulture)) + { + return name.Remove(0, prefix.Length); + } + } + return name; + } + private Tab currentTab; private void SelectTab(Tab tab) { diff --git a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs index 53994493b..29aa5006d 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs @@ -423,7 +423,14 @@ namespace Barotrauma columns++; } - int startX = slot.Rect.Center.X - (int)(subRect.Width * (columns / 2.0f) + spacing.X * ((columns - 1) / 2.0f)); + int width = (int)(subRect.Width * columns + spacing.X * (columns - 1)); + int startX = slot.Rect.Center.X - (int)(width / 2.0f); + + //prevent the inventory from extending outside the left side of the screen + startX = Math.Max(startX, 10); + //same for the right side of the screen + startX -= Math.Max((startX + width) - GameMain.GraphicsWidth, 0); + subRect.X = startX; int startY = dir < 0 ? slot.EquipButtonRect.Y - subRect.Height - (int)(35 * UIScale) : diff --git a/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs b/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs index e98516c90..4d53a8289 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs @@ -29,6 +29,10 @@ namespace Barotrauma drawPos.Y = -drawPos.Y; Color clr = currentHull == null ? Color.Blue : Color.White; + if (isObstructed) + { + clr = Color.Black; + } if (IsSelected) clr = Color.Red; if (IsHighlighted) clr = Color.DarkRed; @@ -50,7 +54,7 @@ namespace Barotrauma GUI.DrawLine(spriteBatch, drawPos, new Vector2(e.DrawPosition.X, -e.DrawPosition.Y), - Color.Green, width: 5); + isObstructed ? Color.Gray : Color.Green, width: 5); } GUI.SmallFont.DrawString(spriteBatch, diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 26e9bdf38..1fabd3482 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -194,8 +194,7 @@ namespace Barotrauma.Networking Hull.EditFire = false; Hull.EditWater = false; - newName = newName.Replace(":", "").Replace(";", ""); - name = newName; + Name = newName; entityEventManager = new ClientEntityEventManager(this); @@ -473,7 +472,8 @@ namespace Barotrauma.Networking var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 0.1f), msgBox.InnerFrame.RectTransform, Anchor.Center) { MinSize = new Point(0, 20) }) { IgnoreLayoutGroups = true, - UserData = "password" + UserData = "password", + Censor = true }; var okButton = msgBox.Buttons[0]; @@ -1303,6 +1303,11 @@ namespace Barotrauma.Networking if (existingClient.ID == myID) { existingClient.SetPermissions(permissions, permittedConsoleCommands); + name = tc.Name; + if (GameMain.NetLobbyScreen.CharacterNameBox != null) + { + GameMain.NetLobbyScreen.CharacterNameBox.Text = name; + } } currentClients.Add(existingClient); } @@ -1562,6 +1567,7 @@ namespace Barotrauma.Networking outmsg.Write(GameMain.NetLobbyScreen.LastUpdateID); outmsg.Write(ChatMessage.LastID); outmsg.Write(LastClientListUpdateID); + outmsg.Write(name); var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign; if (campaign == null || campaign.LastSaveID == 0) @@ -1581,8 +1587,8 @@ namespace Barotrauma.Networking { if (outmsg.LengthBytes + chatMsgQueue[i].EstimateLengthBytesClient() > client.Configuration.MaximumTransmissionUnit - 5) { - //not enough room in this packet - return; + //no more room in this packet + break; } chatMsgQueue[i].ClientWrite(outmsg); } @@ -1617,7 +1623,7 @@ namespace Barotrauma.Networking if (outmsg.LengthBytes + chatMsgQueue[i].EstimateLengthBytesClient() > client.Configuration.MaximumTransmissionUnit - 5) { //not enough room in this packet - return; + break; } chatMsgQueue[i].ClientWrite(outmsg); } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/RespawnManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/RespawnManager.cs index e6458d736..dab9f7392 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/RespawnManager.cs @@ -11,5 +11,15 @@ namespace Barotrauma.Networking respawnTimer = Math.Max(0.0f, respawnTimer - deltaTime); } } + + partial void UpdateTransportingProjSpecific(float deltaTime) + { + if (shuttleTransportTimer + deltaTime > 15.0f && shuttleTransportTimer <= 15.0f && + GameMain.Client?.Character != null && + GameMain.Client.Character.Submarine == respawnShuttle) + { + GameMain.Client.AddChatMessage("ServerMessage.ShuttleLeaving", ChatMessageType.Server); + } + } } } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs b/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs index 68356b34d..0223c9c69 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/ServerInfo.cs @@ -71,15 +71,16 @@ namespace Barotrauma.Networking Stretch = true }; - var titleHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.97f, 0.07f), previewContainer.RectTransform)) + var titleHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), previewContainer.RectTransform)) { IsHorizontal = true, Stretch = true }; - var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), titleHolder.RectTransform), ServerName, font: GUI.LargeFont, wrap: true); + var title = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), titleHolder.RectTransform), ServerName, font: GUI.LargeFont, wrap: true); + title.Text = ToolBox.LimitString(title.Text, title.Font, title.Rect.Width); - new GUITextBlock(new RectTransform(Vector2.One, title.RectTransform), + new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), titleHolder.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("ServerListVersion"), string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion), textAlignment: Alignment.Right); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs index 38b56ce3e..b3c4630fd 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs @@ -63,6 +63,15 @@ namespace Barotrauma.Steam return instance.client.SteamId; } + public static string GetUsername() + { + if (instance == null || !instance.isInitialized) + { + return ""; + } + return instance.client.Username; + } + public static ulong GetWorkshopItemIDFromUrl(string url) { try diff --git a/Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipCapture.cs b/Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipCapture.cs index cd0d3352e..f47145846 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipCapture.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/Voip/VoipCapture.cs @@ -1,6 +1,6 @@ using Lidgren.Network; using Microsoft.Xna.Framework; -using OpenTK.Audio.OpenAL; +using OpenAL; using System; using System.Linq; using System.Runtime.InteropServices; @@ -69,7 +69,7 @@ namespace Barotrauma.Networking VoipConfig.SetupEncoding(); //set up capture device - captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, ALFormat.Mono16, VoipConfig.BUFFER_SIZE * 5); + captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, Al.FormatMono16, VoipConfig.BUFFER_SIZE * 5); if (captureDevice == IntPtr.Zero) { @@ -88,20 +88,20 @@ namespace Barotrauma.Networking return; } - ALError alError = AL.GetError(); - AlcError alcError = Alc.GetError(captureDevice); - if (alcError != AlcError.NoError) + int alError = Al.GetError(); + int alcError = Alc.GetError(captureDevice); + if (alcError != Alc.NoError) { throw new Exception("Failed to open capture device: " + alcError.ToString() + " (ALC)"); } - if (alError != ALError.NoError) + if (alError != Al.NoError) { throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)"); } Alc.CaptureStart(captureDevice); alcError = Alc.GetError(captureDevice); - if (alcError != AlcError.NoError) + if (alcError != Alc.NoError) { throw new Exception("Failed to start capturing: " + alcError.ToString()); } @@ -132,11 +132,11 @@ namespace Barotrauma.Networking short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE]; while (capturing) { - AlcError alcError; - Alc.GetInteger(captureDevice, AlcGetInteger.CaptureSamples, 1, out int sampleCount); + int alcError; + Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out int sampleCount); alcError = Alc.GetError(captureDevice); - if (alcError != AlcError.NoError) + if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } @@ -160,7 +160,7 @@ namespace Barotrauma.Networking } alcError = Alc.GetError(captureDevice); - if (alcError != AlcError.NoError) + if (alcError != Alc.NoError) { throw new Exception("Failed to capture samples: " + alcError.ToString()); } @@ -214,7 +214,7 @@ namespace Barotrauma.Networking } } - Thread.Sleep(VoipConfig.BUFFER_SIZE * 800 / VoipConfig.FREQUENCY); + Thread.Sleep(10); } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index d3b3cde22..408f4d827 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -335,12 +335,6 @@ namespace Barotrauma } subName = doc.Root.GetAttributeString("submarine", ""); saveTime = doc.Root.GetAttributeString("savetime", ""); - - if (long.TryParse(saveTime, out long unixTime)) - { - DateTime time = ToolBox.Epoch.ToDateTime(unixTime); - saveTime = time.ToString(); - } } else { @@ -350,6 +344,11 @@ namespace Barotrauma if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; } if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; } } + if (!string.IsNullOrEmpty(saveTime) && long.TryParse(saveTime, out long unixTime)) + { + DateTime time = ToolBox.Epoch.ToDateTime(unixTime); + saveTime = time.ToString(); + } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform, Anchor.BottomLeft), text: subName, font: GUI.SmallFont) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs index a393d601a..1ec38ed43 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Extensions; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; @@ -231,7 +232,16 @@ namespace Barotrauma "", style: "ItemCategory" + category.ToString()) { UserData = category, - OnClicked = (btn, userdata) => { FilterStoreItems((MapEntityCategory)userdata, searchBox.Text); return true; } + OnClicked = (btn, userdata) => + { + MapEntityCategory newCategory = (MapEntityCategory)userdata; + if (newCategory != selectedItemCategory) + { + searchBox.Text = ""; + } + FilterStoreItems((MapEntityCategory)userdata, searchBox.Text); + return true; + } }; itemCategoryButtons.Add(categoryButton); @@ -487,10 +497,15 @@ namespace Barotrauma { //refresh store view FillStoreItemList(); - FilterStoreItems(MapEntityCategory.Equipment, searchBox.Text); - } + + MapEntityCategory? category = null; + //only select a specific category if the search box is empty + //(items from all categories are shown when searching) + if (string.IsNullOrEmpty(searchBox.Text)) { category = selectedItemCategory; } + FilterStoreItems(category, searchBox.Text); + } } - + private void DrawMap(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { GameMain.GameSession?.Map?.Draw(spriteBatch, mapContainer); @@ -655,7 +670,7 @@ namespace Barotrauma } } - private void CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width) + private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width) { GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.Scale * 50)), listBox.Content.RectTransform), style: "ListBoxElement") { @@ -739,6 +754,10 @@ namespace Barotrauma content.RectTransform.RecalculateChildren(true, true); amountInput?.LayoutGroup.Recalculate(); textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width); + content.RectTransform.IsFixedSize = true; + content.RectTransform.Children.ForEach(c => c.IsFixedSize = true); + + return frame; } private bool BuyItem(GUIComponent component, object obj) @@ -776,12 +795,24 @@ namespace Barotrauma private void RefreshMyItems() { - myItemList.Content.ClearChildren(); - - foreach (PurchasedItem ip in Campaign.CargoManager.PurchasedItems) + HashSet existingItemFrames = new HashSet(); + foreach (PurchasedItem pi in Campaign.CargoManager.PurchasedItems) { - CreateItemFrame(ip, ip.ItemPrefab.GetPrice(Campaign.Map.CurrentLocation), myItemList, myItemList.Rect.Width); + var itemFrame = myItemList.Content.GetChildByUserData(pi); + if (itemFrame == null) + { + itemFrame = CreateItemFrame(pi, pi.ItemPrefab.GetPrice(Campaign.Map.CurrentLocation), myItemList, myItemList.Rect.Width); + } + itemFrame.GetChild(0).GetChild().IntValue = pi.Quantity; + existingItemFrames.Add(itemFrame); } + + var removedItemFrames = myItemList.Content.Children.Except(existingItemFrames).ToList(); + foreach (GUIComponent removedItemFrame in removedItemFrames) + { + myItemList.Content.RemoveChild(removedItemFrame); + } + myItemList.Content.RectTransform.SortChildren((x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name)); myItemList.Content.RectTransform.SortChildren((x, y) => @@ -821,17 +852,28 @@ namespace Barotrauma private void FillStoreItemList() { - storeItemList.ClearChildren(); - int width = storeItemList.Rect.Width; + HashSet existingItemFrames = new HashSet(); foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List) { if (!(mapEntityPrefab is ItemPrefab itemPrefab)) { continue; } PriceInfo priceInfo = itemPrefab.GetPrice(Campaign.Map.CurrentLocation); - if (priceInfo == null) continue; + if (priceInfo == null) { continue; } - CreateItemFrame(new PurchasedItem(itemPrefab, 0), priceInfo, storeItemList, width); + var itemFrame = myItemList.Content.GetChildByUserData(priceInfo); + if (itemFrame == null) + { + itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, 0), priceInfo, storeItemList, width); + } + existingItemFrames.Add(itemFrame); } + + var removedItemFrames = storeItemList.Content.Children.Except(existingItemFrames).ToList(); + foreach (GUIComponent removedItemFrame in removedItemFrames) + { + storeItemList.Content.RemoveChild(removedItemFrame); + } + storeItemList.Content.RectTransform.SortChildren( (x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name)); } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index e4fe091d2..759ab39c1 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -968,7 +968,10 @@ namespace Barotrauma }; label = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("Password"), textAlignment: textAlignment); - passwordBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment); + passwordBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment) + { + Censor = true + }; isPublicBox = new GUITickBox(new RectTransform(tickBoxSize, parent.RectTransform), TextManager.Get("PublicServer")) { diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 3545ce38e..53b26baba 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -147,6 +147,12 @@ namespace Barotrauma get { return playerList; } } + public GUITextBox CharacterNameBox + { + get; + private set; + } + public GUIButton StartButton { get; @@ -920,7 +926,26 @@ namespace Barotrauma UserData = characterInfo }; - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), infoContainer.RectTransform), characterInfo.Name, font: GUI.LargeFont, textAlignment: Alignment.Center, wrap: true); + CharacterNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), infoContainer.RectTransform), characterInfo.Name, font: GUI.LargeFont, textAlignment: Alignment.Center) + { + MaxTextLength = Client.MaxNameLength, + OverflowClip = true + }; + CharacterNameBox.OnEnterPressed += (tb, text) => { CharacterNameBox.Deselect(); return true; }; + CharacterNameBox.OnDeselected += (tb, key) => + { + if (GameMain.Client == null) { return; } + string newName = Client.SanitizeName(tb.Text); + if (string.IsNullOrWhiteSpace(newName)) + { + tb.Text = GameMain.Client.Name; + } + else + { + ReadyToStartBox.Selected = false; + GameMain.Client.Name = tb.Text; + }; + }; GUIComponent headContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.6f, 0.2f), infoContainer.RectTransform, Anchor.TopCenter), isHorizontal: true) { @@ -1309,6 +1334,7 @@ namespace Barotrauma { Selected = true, Enabled = false, + Visible = false, ToolTip = TextManager.Get("ReadyToStartTickBox"), UserData = "clientready" }; diff --git a/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs index f2ec192dd..c8f44567d 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/ServerListScreen.cs @@ -70,8 +70,14 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoHolder.RectTransform), TextManager.Get("YourName")); clientNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.13f), infoHolder.RectTransform), "") { - Text = GameMain.Config.DefaultPlayerName + Text = GameMain.Config.DefaultPlayerName, + MaxTextLength = Client.MaxNameLength, + OverflowClip = true }; + if (string.IsNullOrEmpty(clientNameBox.Text)) + { + clientNameBox.Text = SteamManager.GetUsername(); + } clientNameBox.OnTextChanged += RefreshJoinButtonState; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoHolder.RectTransform), TextManager.Get("ServerIP")); @@ -236,7 +242,7 @@ namespace Barotrauma { serverInfo = (ServerInfo)obj; ipBox.UserData = serverInfo; - ipBox.Text = serverInfo.ServerName; + ipBox.Text = ToolBox.LimitString(serverInfo.ServerName, ipBox.Font, ipBox.Rect.Width); } catch (InvalidCastException) { @@ -411,7 +417,6 @@ namespace Barotrauma }; var serverName = new GUITextBlock(new RectTransform(new Vector2(columnRelativeWidth[3], 1.0f), serverContent.RectTransform), serverInfo.ServerName, style: "GUIServerListTextBox"); - var gameStartedBox = new GUITickBox(new RectTransform(new Vector2(columnRelativeWidth[4], 0.4f), serverContent.RectTransform, Anchor.Center), label: "", style: "GUIServerListRoundStartedTickBox") { ToolTip = TextManager.Get((serverInfo.GameStarted) ? "ServerListRoundStarted" : "ServerListRoundNotStarted"), diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs index dacc02b24..7f59ebd1e 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/OggSound.cs @@ -1,5 +1,5 @@ using System; -using OpenTK.Audio.OpenAL; +using OpenAL; using NVorbis; using System.Collections.Generic; @@ -21,7 +21,7 @@ namespace Barotrauma.Sounds reader = new VorbisReader(filename); - ALFormat = reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16; + ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16; SampleRate = reader.SampleRate; if (!stream) @@ -35,26 +35,26 @@ namespace Barotrauma.Sounds CastBuffer(floatBuffer, shortBuffer, readSamples); - AL.BufferData((int)ALBuffer, ALFormat, shortBuffer, + Al.BufferData(ALBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set buffer data for non-streamed audio! "+AL.GetErrorString(alError)); + throw new Exception("Failed to set buffer data for non-streamed audio! "+Al.GetErrorString(alError)); } MuffleBuffer(floatBuffer, SampleRate, reader.Channels); CastBuffer(floatBuffer, shortBuffer, readSamples); - AL.BufferData((int)ALMuffledBuffer, ALFormat, shortBuffer, + Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set buffer data for non-streamed audio! " + AL.GetErrorString(alError)); + throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } reader.Dispose(); @@ -98,4 +98,4 @@ namespace Barotrauma.Sounds base.Dispose(); } } -} \ No newline at end of file +} diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs index c3b0a474b..a5685cbd1 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/Sound.cs @@ -1,5 +1,5 @@ using System; -using OpenTK.Audio.OpenAL; +using OpenAL; using Microsoft.Xna.Framework; using System.IO; @@ -57,7 +57,7 @@ namespace Barotrauma.Sounds get { return !Stream ? alMuffledBuffer : 0; } } - public ALFormat ALFormat + public int ALFormat { get; protected set; @@ -91,26 +91,26 @@ namespace Barotrauma.Sounds if (!stream) { - AL.GenBuffer(out alBuffer); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.GenBuffer(out alBuffer); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + AL.GetErrorString(alError)); + throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } - if (!AL.IsBuffer(alBuffer)) + if (!Al.IsBuffer(alBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } - AL.GenBuffer(out alMuffledBuffer); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.GenBuffer(out alMuffledBuffer); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + AL.GetErrorString(alError)); + throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } - if (!AL.IsBuffer(alMuffledBuffer)) + if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } @@ -186,32 +186,32 @@ namespace Barotrauma.Sounds Owner.KillChannels(this); if (alBuffer != 0) { - if (!AL.IsBuffer(alBuffer)) + if (!Al.IsBuffer(alBuffer)) { throw new Exception("Buffer to delete is invalid!"); } - AL.DeleteBuffer(ref alBuffer); alBuffer = 0; + Al.DeleteBuffer(alBuffer); alBuffer = 0; - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + AL.GetErrorString(alError)); + throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } if (alMuffledBuffer != 0) { - if (!AL.IsBuffer(alMuffledBuffer)) + if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Buffer to delete is invalid!"); } - AL.DeleteBuffer(ref alMuffledBuffer); alMuffledBuffer = 0; + Al.DeleteBuffer(alMuffledBuffer); alMuffledBuffer = 0; - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + AL.GetErrorString(alError)); + throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs b/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs index e939f97bd..a69f4b102 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/SoundChannel.cs @@ -1,5 +1,5 @@ using System; -using OpenTK.Audio.OpenAL; +using OpenAL; using Microsoft.Xna.Framework; using System.Collections.Generic; @@ -15,49 +15,49 @@ namespace Barotrauma.Sounds public SoundSourcePool(int sourceCount = SoundManager.SOURCE_COUNT) { - ALError alError = ALError.NoError; + int alError = Al.NoError; ALSources = new uint[sourceCount]; for (int i = 0; i < sourceCount; i++) { - AL.GenSource(out ALSources[i]); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.GenSource(out ALSources[i]); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Error generating alSource[" + i.ToString() + "]: " + AL.GetErrorString(alError)); + throw new Exception("Error generating alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } - if (!AL.IsSource(ALSources[i])) + if (!Al.IsSource(ALSources[i])) { throw new Exception("Generated alSource[" + i.ToString() + "] is invalid!"); } - AL.SourceStop(ALSources[i]); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourceStop(ALSources[i]); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + AL.GetErrorString(alError)); + throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } - AL.Source(ALSources[i], ALSourcef.MinGain, 0.0f); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcef(ALSources[i], Al.MinGain, 0.0f); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Error setting min gain: " + AL.GetErrorString(alError)); + throw new Exception("Error setting min gain: " + Al.GetErrorString(alError)); } - AL.Source(ALSources[i], ALSourcef.MaxGain, 1.0f); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcef(ALSources[i], Al.MaxGain, 1.0f); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Error setting max gain: " + AL.GetErrorString(alError)); + throw new Exception("Error setting max gain: " + Al.GetErrorString(alError)); } - AL.Source(ALSources[i], ALSourcef.RolloffFactor, 1.0f); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcef(ALSources[i], Al.RolloffFactor, 1.0f); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Error setting rolloff factor: " + AL.GetErrorString(alError)); + throw new Exception("Error setting rolloff factor: " + Al.GetErrorString(alError)); } } } @@ -66,11 +66,11 @@ namespace Barotrauma.Sounds { for (int i = 0; i < ALSources.Length; i++) { - AL.DeleteSource(ref ALSources[i]); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.DeleteSource(ALSources[i]); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to delete ALSources[" + i.ToString() + "]: " + AL.GetErrorString(alError)); + throw new Exception("Failed to delete ALSources[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } } ALSources = null; @@ -95,35 +95,35 @@ namespace Barotrauma.Sounds if (position != null) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.Source(alSource, ALSourceb.SourceRelative, false); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(alSource, Al.SourceRelative, Al.False); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to enable source's relative flag: " + AL.GetErrorString(alError)); + throw new Exception("Failed to enable source's relative flag: " + Al.GetErrorString(alError)); } - AL.Source(alSource, ALSource3f.Position, position.Value.X, position.Value.Y, position.Value.Z); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Source3f(alSource, Al.Position, position.Value.X, position.Value.Y, position.Value.Z); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set source's position: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set source's position: " + Al.GetErrorString(alError)); } } else { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.Source(alSource, ALSourceb.SourceRelative, true); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(alSource, Al.SourceRelative, Al.True); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to disable source's relative flag: " + AL.GetErrorString(alError)); + throw new Exception("Failed to disable source's relative flag: " + Al.GetErrorString(alError)); } - AL.Source(alSource, ALSource3f.Position, 0.0f, 0.0f, 0.0f); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Source3f(alSource, Al.Position, 0.0f, 0.0f, 0.0f); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to reset source's position: " + AL.GetErrorString(alError)); + throw new Exception("Failed to reset source's position: " + Al.GetErrorString(alError)); } } } @@ -140,12 +140,12 @@ namespace Barotrauma.Sounds if (ALSourceIndex < 0) return; uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.Source(alSource, ALSourcef.ReferenceDistance, near); + Al.Sourcef(alSource, Al.ReferenceDistance, near); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set source's reference distance: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set source's reference distance: " + Al.GetErrorString(alError)); } } } @@ -161,11 +161,11 @@ namespace Barotrauma.Sounds if (ALSourceIndex < 0) return; uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.Source(alSource, ALSourcef.MaxDistance, far); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcef(alSource, Al.MaxDistance, far); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set source's max distance: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set source's max distance: " + Al.GetErrorString(alError)); } } } @@ -185,11 +185,11 @@ namespace Barotrauma.Sounds float effectiveGain = gain; if (category != null) effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category); - AL.Source(alSource, ALSourcef.Gain, effectiveGain); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcef(alSource, Al.Gain, effectiveGain); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set source's gain: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set source's gain: " + Al.GetErrorString(alError)); } } } @@ -207,11 +207,11 @@ namespace Barotrauma.Sounds if (!IsStream) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.Source(alSource, ALSourceb.Looping, looping); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(alSource, Al.Looping, looping ? Al.True : Al.False); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set source's looping state: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set source's looping state: " + Al.GetErrorString(alError)); } } } @@ -242,41 +242,41 @@ namespace Barotrauma.Sounds if (!IsStream) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - int playbackPos; AL.GetSource(alSource, ALGetSourcei.SampleOffset, out playbackPos); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int playbackPos; Al.GetSourcei(alSource, Al.SampleOffset, out playbackPos); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to get source's playback position: " + AL.GetErrorString(alError)); + throw new Exception("Failed to get source's playback position: " + Al.GetErrorString(alError)); } - AL.SourceStop(alSource); + Al.SourceStop(alSource); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to stop source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to stop source: " + Al.GetErrorString(alError)); } - AL.BindBufferToSource(alSource,(uint)(muffled ? Sound.ALMuffledBuffer : Sound.ALBuffer)); + Al.Sourcei(alSource, Al.Buffer, muffled ? (int)Sound.ALMuffledBuffer : (int)Sound.ALBuffer); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to bind buffer to source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to bind buffer to source: " + Al.GetErrorString(alError)); } - AL.SourcePlay(alSource); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourcePlay(alSource); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to replay source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to replay source: " + Al.GetErrorString(alError)); } - AL.Source(alSource, ALSourcei.SampleOffset, playbackPos); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(alSource, Al.SampleOffset, playbackPos); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to reset playback position: " + AL.GetErrorString(alError)); + throw new Exception("Failed to reset playback position: " + Al.GetErrorString(alError)); } } } @@ -324,11 +324,13 @@ namespace Barotrauma.Sounds { if (ALSourceIndex < 0) return false; if (IsStream && !reachedEndSample) return true; - bool playing = AL.GetSourceState(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)) == ALSourceState.Playing; - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int state; + Al.GetSourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.SourceState, out state); + bool playing = state == Al.Playing; + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to determine playing state from source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to determine playing state from source: " + Al.GetErrorString(alError)); } return playing; } @@ -357,47 +359,47 @@ namespace Barotrauma.Sounds { if (!IsStream) { - AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), 0); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to reset source buffer: " + AL.GetErrorString(alError)); + throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError)); } - if (!AL.IsBuffer(sound.ALBuffer)) + if (!Al.IsBuffer(sound.ALBuffer)) { throw new Exception(sound.Filename + " has an invalid buffer!"); } uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer; - AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), alBuffer); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + AL.GetErrorString(alError)); + throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + Al.GetErrorString(alError)); } - AL.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to play source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to play source: " + Al.GetErrorString(alError)); } } else { - AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), (uint)sound.ALBuffer); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)sound.ALBuffer); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to reset source buffer: " + AL.GetErrorString(alError)); + throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError)); } - AL.Source(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), ALSourceb.Looping, false); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Looping, Al.False); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set stream looping state: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set stream looping state: " + Al.GetErrorString(alError)); } streamShortBuffer = new short[STREAM_BUFFER_SIZE]; @@ -406,15 +408,15 @@ namespace Barotrauma.Sounds emptyBuffers = new List(); for (int i = 0; i < 4; i++) { - AL.GenBuffer(out streamBuffers[i]); + Al.GenBuffer(out streamBuffers[i]); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to generate stream buffers: " + AL.GetErrorString(alError)); + throw new Exception("Failed to generate stream buffers: " + Al.GetErrorString(alError)); } - if (!AL.IsBuffer(streamBuffers[i])) + if (!Al.IsBuffer(streamBuffers[i])) { throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid!"); } @@ -445,57 +447,57 @@ namespace Barotrauma.Sounds { if (ALSourceIndex >= 0) { - AL.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to stop source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to stop source: " + Al.GetErrorString(alError)); } if (IsStream) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - AL.SourceStop(alSource); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourceStop(alSource); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to stop streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to stop streamed source: " + Al.GetErrorString(alError)); } int buffersToUnqueue = 0; - int[] unqueuedBuffers = null; + uint[] unqueuedBuffers = null; buffersToUnqueue = 0; - AL.GetSource(alSource, ALGetSourcei.BuffersProcessed, out buffersToUnqueue); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to determine processed buffers from streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError)); } - unqueuedBuffers = new int[buffersToUnqueue]; - AL.SourceUnqueueBuffers((int)alSource, buffersToUnqueue, unqueuedBuffers); - alError = AL.GetError(); - if (alError != ALError.NoError) + unqueuedBuffers = new uint[buffersToUnqueue]; + Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to unqueue buffers from streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError)); } - - AL.BindBufferToSource(alSource, 0); - alError = AL.GetError(); - if (alError != ALError.NoError) + + Al.Sourcei(alSource, Al.Buffer, 0); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to reset buffer for streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to reset buffer for streamed source: " + Al.GetErrorString(alError)); } for (int i = 0; i < 4; i++) { - AL.DeleteBuffer(ref streamBuffers[i]); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.DeleteBuffer(streamBuffers[i]); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to delete streamBuffers[" + i.ToString() + "] ("+streamBuffers[i].ToString()+"): " + AL.GetErrorString(alError)); + throw new Exception("Failed to delete streamBuffers[" + i.ToString() + "] ("+streamBuffers[i].ToString()+"): " + Al.GetErrorString(alError)); } } @@ -503,11 +505,11 @@ namespace Barotrauma.Sounds } else { - AL.BindBufferToSource(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), 0); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Sourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to unbind buffer to non-streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to unbind buffer to non-streamed source: " + Al.GetErrorString(alError)); } } @@ -526,47 +528,49 @@ namespace Barotrauma.Sounds { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); - bool playing = AL.GetSourceState(alSource) == ALSourceState.Playing; - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + int state; + Al.GetSourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.SourceState, out state); + bool playing = state == Al.Playing; + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to determine playing state from streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to determine playing state from streamed source: " + Al.GetErrorString(alError)); } int buffersToUnqueue = 0; - int[] unqueuedBuffers = null; + uint[] unqueuedBuffers = null; if (!startedPlaying) { buffersToUnqueue = 0; - AL.GetSource(alSource, ALGetSourcei.BuffersProcessed, out buffersToUnqueue); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to determine processed buffers from streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError)); } - unqueuedBuffers = new int[buffersToUnqueue+emptyBuffers.Count]; - AL.SourceUnqueueBuffers((int)alSource, buffersToUnqueue, unqueuedBuffers); + unqueuedBuffers = new uint[buffersToUnqueue+emptyBuffers.Count]; + Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers); for (int i = 0; i < emptyBuffers.Count; i++) { - unqueuedBuffers[buffersToUnqueue + i] = (int)emptyBuffers[i]; + unqueuedBuffers[buffersToUnqueue + i] = emptyBuffers[i]; } buffersToUnqueue += emptyBuffers.Count; emptyBuffers.Clear(); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to unqueue buffers from streamed source: " + AL.GetErrorString(alError)); + throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError)); } } else { startedPlaying = false; buffersToUnqueue = 4; - unqueuedBuffers = new int[4]; + unqueuedBuffers = new uint[4]; for (int i = 0; i < 4; i++) { - unqueuedBuffers[i] = (int)streamBuffers[i]; + unqueuedBuffers[i] = streamBuffers[i]; } } @@ -612,20 +616,20 @@ namespace Barotrauma.Sounds if (readSamples > 0) { - AL.BufferData(unqueuedBuffers[i], Sound.ALFormat, buffer, readSamples, Sound.SampleRate); + Al.BufferData(unqueuedBuffers[i], Sound.ALFormat, buffer, readSamples, Sound.SampleRate); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { throw new Exception("Failed to assign data to stream buffer: " + - AL.GetErrorString(alError) + ": " + unqueuedBuffers[i].ToString() + "/" + unqueuedBuffers.Length + ", readSamples: " + readSamples); + Al.GetErrorString(alError) + ": " + unqueuedBuffers[i].ToString() + "/" + unqueuedBuffers.Length + ", readSamples: " + readSamples); } - AL.SourceQueueBuffer((int)alSource, unqueuedBuffers[i]); - alError = AL.GetError(); - if (alError != ALError.NoError) + Al.SourceQueueBuffer(alSource, unqueuedBuffers[i]); + alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to queue buffer[" + i.ToString() + "] to stream: " + AL.GetErrorString(alError)); + throw new Exception("Failed to queue buffer[" + i.ToString() + "] to stream: " + Al.GetErrorString(alError)); } } else if (readSamples < 0) @@ -637,10 +641,11 @@ namespace Barotrauma.Sounds emptyBuffers.Add((uint)unqueuedBuffers[i]); } } - - if (AL.GetSourceState(alSource) != ALSourceState.Playing) + + Al.GetSourcei(alSource, Al.SourceState, out state); + if (state != Al.Playing) { - AL.SourcePlay(alSource); + Al.SourcePlay(alSource); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs b/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs index 14807564c..9948f044e 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/SoundManager.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Collections.Generic; using System.Xml.Linq; -using OpenTK.Audio.OpenAL; +using OpenAL; using Microsoft.Xna.Framework; using System.Linq; using System.IO; @@ -20,7 +20,7 @@ namespace Barotrauma.Sounds } private IntPtr alcDevice; - private OpenTK.ContextHandle alcContext; + private IntPtr alcContext; public enum SourcePoolIndex { @@ -42,11 +42,11 @@ namespace Barotrauma.Sounds { if (Disabled) { return; } listenerPosition = value; - AL.Listener(ALListener3f.Position,value.X,value.Y,value.Z); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Listener3f(Al.Position,value.X,value.Y,value.Z); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set listener position: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set listener position: " + Al.GetErrorString(alError)); } } } @@ -59,11 +59,11 @@ namespace Barotrauma.Sounds { if (Disabled) { return; } listenerOrientation[0] = value.X; listenerOrientation[1] = value.Y; listenerOrientation[2] = value.Z; - AL.Listener(ALListenerfv.Orientation, ref listenerOrientation); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Listenerfv(Al.Orientation, listenerOrientation); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set listener target vector: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set listener target vector: " + Al.GetErrorString(alError)); } } } @@ -74,11 +74,11 @@ namespace Barotrauma.Sounds { if (Disabled) { return; } listenerOrientation[3] = value.X; listenerOrientation[4] = value.Y; listenerOrientation[5] = value.Z; - AL.Listener(ALListenerfv.Orientation, ref listenerOrientation); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Listenerfv(Al.Orientation, listenerOrientation); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set listener up vector: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set listener up vector: " + Al.GetErrorString(alError)); } } } @@ -92,11 +92,11 @@ namespace Barotrauma.Sounds if (Disabled) { return; } if (Math.Abs(ListenerGain - value) < 0.001f) { return; } listenerGain = value; - AL.Listener(ALListenerf.Gain, listenerGain); - ALError alError = AL.GetError(); - if (alError != ALError.NoError) + Al.Listenerf(Al.Gain, listenerGain); + int alError = Al.GetError(); + if (alError != Al.NoError) { - throw new Exception("Failed to set listener gain: " + AL.GetErrorString(alError)); + throw new Exception("Failed to set listener gain: " + Al.GetErrorString(alError)); } } } @@ -126,8 +126,8 @@ namespace Barotrauma.Sounds return; } - AlcError alcError = Alc.GetError(alcDevice); - if (alcError != AlcError.NoError) + int alcError = Alc.GetError(alcDevice); + if (alcError != Alc.NoError) { //The audio device probably wasn't ready, this happens quite often //Just wait a while and try again @@ -136,7 +136,7 @@ namespace Barotrauma.Sounds alcDevice = Alc.OpenDevice(null); alcError = Alc.GetError(alcDevice); - if (alcError != AlcError.NoError) + if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error initializing ALC device: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; @@ -161,14 +161,14 @@ namespace Barotrauma.Sounds } alcError = Alc.GetError(alcDevice); - if (alcError != AlcError.NoError) + if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return; } - ALError alError = ALError.NoError; + int alError = Al.NoError; sourcePools = new SoundSourcePool[2]; sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); @@ -177,12 +177,12 @@ namespace Barotrauma.Sounds sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(8); playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[8]; - AL.DistanceModel(ALDistanceModel.LinearDistanceClamped); + Al.DistanceModel(Al.LinearDistanceClamped); - alError = AL.GetError(); - if (alError != ALError.NoError) + alError = Al.GetError(); + if (alError != Al.NoError) { - DebugConsole.ThrowError("Error setting distance model: " + AL.GetErrorString(alError) + ". Disabling audio playback..."); + DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback..."); Disabled = true; return; } @@ -239,7 +239,7 @@ namespace Barotrauma.Sounds { if (Disabled || srcInd < 0 || srcInd >= sourcePools[(int)poolIndex].ALSources.Length) return 0; - if (!AL.IsSource(sourcePools[(int)poolIndex].ALSources[srcInd])) + if (!Al.IsSource(sourcePools[(int)poolIndex].ALSources[srcInd])) { throw new Exception("alSources[" + srcInd.ToString() + "] is invalid!"); } @@ -276,8 +276,8 @@ namespace Barotrauma.Sounds { for (int i = 0; i < sourcePools[0].ALSources.Length; i++) { - AL.Source(sourcePools[0].ALSources[i], ALSourcef.MaxGain, i == ind ? 1.0f : 0.0f); - AL.Source(sourcePools[0].ALSources[i], ALSourcef.MinGain, 0.0f); + Al.Sourcef(sourcePools[0].ALSources[i], Al.MaxGain, i == ind ? 1.0f : 0.0f); + Al.Sourcef(sourcePools[0].ALSources[i], Al.MinGain, 0.0f); } } #endif @@ -503,10 +503,7 @@ namespace Barotrauma.Sounds } } } - if (streamingThread != null && !streamingThread.ThreadState.HasFlag(ThreadState.Stopped)) - { - streamingThread.Join(); - } + streamingThread?.Join(); for (int i = loadedSounds.Count - 1; i >= 0; i--) { loadedSounds[i].Dispose(); @@ -514,7 +511,7 @@ namespace Barotrauma.Sounds sourcePools[(int)SourcePoolIndex.Default]?.Dispose(); sourcePools[(int)SourcePoolIndex.Voice]?.Dispose(); - if (!Alc.MakeContextCurrent(OpenTK.ContextHandle.Zero)) + if (!Alc.MakeContextCurrent(IntPtr.Zero)) { throw new Exception("Failed to detach the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + ")"); } diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/VideoSound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/VideoSound.cs index ff877c8a0..011d557ab 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/VideoSound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/VideoSound.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using OpenTK.Audio.OpenAL; +using OpenAL; using Microsoft.Xna.Framework; using System.Runtime.InteropServices; using System.Threading; @@ -21,7 +21,7 @@ namespace Barotrauma.Sounds public VideoSound(SoundManager owner, string filename, int sampleRate, Video vid) : base(owner, filename, true, false) { - ALFormat = ALFormat.Stereo16; + ALFormat = Al.FormatStereo16; SampleRate = sampleRate; sampleQueue = new Queue(); @@ -110,4 +110,4 @@ namespace Barotrauma.Sounds } } } -} \ No newline at end of file +} diff --git a/Barotrauma/BarotraumaClient/Source/Sounds/VoipSound.cs b/Barotrauma/BarotraumaClient/Source/Sounds/VoipSound.cs index 18126a8ba..5eb8ad951 100644 --- a/Barotrauma/BarotraumaClient/Source/Sounds/VoipSound.cs +++ b/Barotrauma/BarotraumaClient/Source/Sounds/VoipSound.cs @@ -1,6 +1,6 @@ using Barotrauma.Networking; using Microsoft.Xna.Framework; -using OpenTK.Audio.OpenAL; +using OpenAL; using System; using System.Collections.Generic; @@ -58,7 +58,7 @@ namespace Barotrauma.Sounds { VoipConfig.SetupEncoding(); - ALFormat = ALFormat.Mono16; + ALFormat = Al.FormatMono16; SampleRate = VoipConfig.FREQUENCY; queue = q; diff --git a/Barotrauma/BarotraumaClient/Source/Sprite/DeformAnimations/SpriteDeformation.cs b/Barotrauma/BarotraumaClient/Source/Sprite/DeformAnimations/SpriteDeformation.cs index 19097bf21..da7364bcc 100644 --- a/Barotrauma/BarotraumaClient/Source/Sprite/DeformAnimations/SpriteDeformation.cs +++ b/Barotrauma/BarotraumaClient/Source/Sprite/DeformAnimations/SpriteDeformation.cs @@ -40,6 +40,9 @@ namespace Barotrauma.SpriteDeformations [Serialize(false, true)] public bool UseMovementSine { get; set; } + [Serialize(false, true)] + public bool StopWhenHostIsDead { get; set; } + /// /// Only used if UseMovementSine is enabled. Multiplier for Pi. /// diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index dc6b33c63..151864bcf 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -31,7 +31,7 @@ true - .pdb + .pdb ..\BarotraumaShared\Icon.ico @@ -39,7 +39,7 @@ true ..\bin\ReleaseWindows\ - TRACE;WINDOWS;CLIENT + TRACE;WINDOWS;CLIENT;X64 true pdbonly x64 @@ -49,7 +49,7 @@ true ..\bin\DebugWindows\ - TRACE;WINDOWS;CLIENT;DEBUG + TRACE;DEBUG;WINDOWS;CLIENT;X64 full x64 MinimumRecommendedRules.ruleset @@ -60,7 +60,7 @@ true ..\bin\x86\ReleaseWindows\ - TRACE;WINDOWS;CLIENT + TRACE;WINDOWS;CLIENT;X86 true pdbonly x86 @@ -70,7 +70,7 @@ true ..\bin\x86\DebugWindows\ - TRACE;WINDOWS;CLIENT;DEBUG + TRACE;DEBUG;WINDOWS;CLIENT;X86 full x86 MinimumRecommendedRules.ruleset @@ -95,9 +95,6 @@ ..\..\Libraries\NuGet\NVorbis.0.8.6\lib\net35\NVorbis.dll - - ..\..\Libraries\NuGet\OpenTK.3.0.1\lib\net20\OpenTK.dll - ..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll @@ -215,16 +212,16 @@ - - PreserveNewest - PreserveNewest - + PreserveNewest - + + PreserveNewest + + PreserveNewest @@ -306,7 +303,7 @@ - + diff --git a/Barotrauma/BarotraumaClient/packages.config b/Barotrauma/BarotraumaClient/packages.config index e593ce09a..72a6ec439 100644 --- a/Barotrauma/BarotraumaClient/packages.config +++ b/Barotrauma/BarotraumaClient/packages.config @@ -8,7 +8,6 @@ - diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 34eab06f2..b38e34012 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.9.0.3")] -[assembly: AssemblyFileVersion("0.9.0.3")] +[assembly: AssemblyVersion("0.9.0.4")] +[assembly: AssemblyFileVersion("0.9.0.4")] diff --git a/Barotrauma/BarotraumaServer/Server.csproj b/Barotrauma/BarotraumaServer/Server.csproj index 6b66b1b69..9d9e7370d 100644 --- a/Barotrauma/BarotraumaServer/Server.csproj +++ b/Barotrauma/BarotraumaServer/Server.csproj @@ -273,10 +273,7 @@ - - - PreserveNewest - + PreserveNewest diff --git a/Barotrauma/BarotraumaServer/Source/Networking/Client.cs b/Barotrauma/BarotraumaServer/Source/Networking/Client.cs index 28e291e39..611793855 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/Client.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/Client.cs @@ -153,20 +153,5 @@ namespace Barotrauma.Networking { return this.Permissions.HasFlag(permission); } - - public static string SanitizeName(string name) - { - name = name.Trim(); - if (name.Length > 20) - { - name = name.Substring(0, 20); - } - string rName = ""; - for (int i = 0; i < name.Length; i++) - { - rName += name[i] < 32 ? '?' : name[i]; - } - return rName; - } } } diff --git a/Barotrauma/BarotraumaServer/Source/Networking/EntitySpawner.cs b/Barotrauma/BarotraumaServer/Source/Networking/EntitySpawner.cs index 1f295253f..45eb98b16 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/EntitySpawner.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/EntitySpawner.cs @@ -30,12 +30,13 @@ namespace Barotrauma if (entities.Entity is Item) { message.Write((byte)SpawnableType.Item); + DebugConsole.Log("Writing item spawn data " + entities.Entity.ToString() + " (ID: " + entities.Entity.ID + ")"); ((Item)entities.Entity).WriteSpawnData(message); } else if (entities.Entity is Character) { message.Write((byte)SpawnableType.Character); - DebugConsole.NewMessage("WRITING CHARACTER DATA: " + (entities.Entity).ToString() + " (ID: " + entities.Entity.ID + ")", Color.Cyan); + DebugConsole.Log("Writing character spawn data: " + entities.Entity.ToString() + " (ID: " + entities.Entity.ID + ")"); ((Character)entities.Entity).WriteSpawnData(message); } } diff --git a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs index 1dbc815cb..4e884f7fc 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs @@ -576,7 +576,7 @@ namespace Barotrauma.Networking HandleOwnership(msgContent, inc.SenderConnection); } - DebugConsole.NewMessage(packetHeader.ToString(), Color.Lime); + DebugConsole.Log(packetHeader.ToString()); if (inc.SenderConnection != OwnerConnection && serverSettings.BanList.IsBanned(inc.SenderEndPoint.Address, 0)) { inc.SenderConnection.Deny(DisconnectReason.Banned.ToString()); @@ -661,7 +661,13 @@ namespace Barotrauma.Networking if (GameMain.Config.UseSteamMatchmaking) { - SteamManager.RefreshServerDetails(this); + bool refreshSuccessful = SteamManager.RefreshServerDetails(this); + if (GameSettings.VerboseLogging) + { + Log(refreshSuccessful ? + "Refreshed server info on the server list." : + "Refreshing server info on the server list failed.", ServerLog.MessageType.ServerMessage); + } } else { @@ -865,6 +871,8 @@ namespace Barotrauma.Networking c.LastRecvLobbyUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvLobbyUpdate, GameMain.NetLobbyScreen.LastUpdateID); c.LastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvChatMsgID, c.LastChatMsgQueueID); c.LastRecvClientListUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvClientListUpdate, LastClientListUpdateID); + + TryChangeClientName(c, inc.ReadString()); c.LastRecvCampaignSave = inc.ReadUInt16(); if (c.LastRecvCampaignSave > 0) @@ -2066,11 +2074,44 @@ namespace Barotrauma.Networking public override void AddChatMessage(ChatMessage message) { if (string.IsNullOrEmpty(message.Text)) { return; } - Log(message.TextWithSender, ServerLog.MessageType.Chat); + Log(message.TextWithSender, ServerLog.MessageType.Chat); base.AddChatMessage(message); } + private bool TryChangeClientName(Client c, string newName) + { + if (c == null || string.IsNullOrEmpty(newName)) { return false; } + + newName = Client.SanitizeName(newName); + if (newName == c.Name) { return false; } + + //update client list even if the name cannot be changed to the one sent by the client, + //so the client will be informed what their actual name is + LastClientListUpdateID++; + + if (!Client.IsValidName(newName, this)) + { + SendDirectChatMessage("Could not change your name to \"" + newName + "\" (the name contains disallowed symbols).", c, ChatMessageType.MessageBox); + return false; + } + if (c.Connection != OwnerConnection && Homoglyphs.Compare(newName.ToLower(), Name.ToLower())) + { + SendDirectChatMessage("Could not change your name to \"" + newName + "\" (too similar to the server's name).", c, ChatMessageType.MessageBox); + return false; + } + Client nameTaken = ConnectedClients.Find(c2 => c != c2 && Homoglyphs.Compare(c2.Name.ToLower(), newName.ToLower())); + if (nameTaken != null) + { + SendDirectChatMessage("Could not change your name to \"" + newName + "\" (too similar to the name of the client \"" + nameTaken.Name + "\").", c, ChatMessageType.MessageBox); + return false; + } + + SendChatMessage("Player \"" + c.Name + "\" has changed their name to \"" + newName + "\".", ChatMessageType.Server); + c.Name = newName; + return true; + } + public override void KickPlayer(string playerName, string reason) { playerName = playerName.ToLowerInvariant(); diff --git a/Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs b/Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs index 2d720f969..3091825e5 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs @@ -432,7 +432,7 @@ namespace Barotrauma.Networking DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red); return; } - if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(),Name.ToLower())) + if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(), Name.ToLower())) { DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, ""); Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error); diff --git a/Barotrauma/BarotraumaServer/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Barotrauma/BarotraumaServer/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs index d1d613a94..dc2fdfce9 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -48,6 +48,9 @@ namespace Barotrauma.Networking private List uniqueEvents; private UInt16 lastSentToAll; + private UInt16 lastSentToAnyone; + private double lastSentToAnyoneTime; + private double lastWarningTime; public List Events { @@ -99,6 +102,8 @@ namespace Barotrauma.Networking bufferedEvents = new List(); uniqueEvents = new List(); + + lastWarningTime = -10.0; } public void CreateEvent(IServerSerializable entity, object[] extraData = null) @@ -198,6 +203,7 @@ namespace Barotrauma.Networking var inGameClients = clients.FindAll(c => c.InGame && !c.NeedsMidRoundSync); if (inGameClients.Count > 0) { + lastSentToAnyone = inGameClients[0].LastRecvEntityEventID; lastSentToAll = inGameClients[0].LastRecvEntityEventID; if (server.OwnerConnection != null) { @@ -207,25 +213,39 @@ namespace Barotrauma.Networking lastSentToAll = owner.LastRecvEntityEventID; } } - inGameClients.ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.LastRecvEntityEventID)) lastSentToAll = c.LastRecvEntityEventID; }); + inGameClients.ForEach(c => + { + if (NetIdUtils.IdMoreRecent(lastSentToAll, c.LastRecvEntityEventID)) { lastSentToAll = c.LastRecvEntityEventID; } + if (NetIdUtils.IdMoreRecent(c.LastRecvEntityEventID, lastSentToAnyone)) { lastSentToAnyone = c.LastRecvEntityEventID; } + }); + lastSentToAnyoneTime = events.Find(e => e.ID == lastSentToAnyone)?.CreateTime ?? Timing.TotalTime; + if ((Timing.TotalTime - lastSentToAnyoneTime) > 10.0 && (Timing.TotalTime - lastWarningTime) > 5.0) + { + lastWarningTime = Timing.TotalTime; + GameServer.Log("WARNING: ServerEntityEventManager is lagging behind! Last sent id: " + lastSentToAnyone.ToString() + ", latest create id: " + ID.ToString(), ServerLog.MessageType.ServerMessage); + //TODO: reset clients if this happens, maybe do it if a majority are behind rather than all of them? + } + clients.Where(c => c.NeedsMidRoundSync).ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.FirstNewEventID)) lastSentToAll = (ushort)(c.FirstNewEventID - 1); }); ServerEntityEvent firstEventToResend = events.Find(e => e.ID == (ushort)(lastSentToAll + 1)); - if (firstEventToResend != null && (Timing.TotalTime - firstEventToResend.CreateTime) > 10.0f) + if (firstEventToResend != null && ((lastSentToAnyoneTime - firstEventToResend.CreateTime) > 10.0 || (Timing.TotalTime - firstEventToResend.CreateTime) > 30.0)) { - //it's been 10 seconds since this event was created, kick everyone that hasn't received it yet, this is way too old - // UNLESS the event was created when the client was still midround syncing, in which case we'll wait until the timeout - // runs out before kicking the client + // This event is 10 seconds older than the last one we've successfully sent, + // kick everyone that hasn't received it yet, this is way too old + // UNLESS the event was created when the client was still midround syncing, + // in which case we'll wait until the timeout runs out before kicking the client List toKick = inGameClients.FindAll(c => NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) && - (firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut)); + (firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut)); toKick.ForEach(c => { DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected old event " + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red); GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event " + (c.LastRecvEntityEventID + 1).ToString() + - " (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago)" + + " (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " + + (lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" + " Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error); server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncOldEvent"); } diff --git a/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs b/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs index a27e15083..dcd655cbd 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/RespawnManager.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Items.Components; +using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Linq; @@ -9,19 +10,15 @@ namespace Barotrauma.Networking { private List GetClientsToRespawn() { - GameServer server = networkMember as GameServer; - return networkMember.ConnectedClients.FindAll(c => c.InGame && - (!c.SpectateOnly || (!server.ServerSettings.AllowSpectating && server.OwnerConnection != c.Connection)) && + (!c.SpectateOnly || (!GameMain.Server.ServerSettings.AllowSpectating && GameMain.Server.OwnerConnection != c.Connection)) && (c.Character == null || c.Character.IsDead)); } private List GetBotsToRespawn() { - GameServer server = networkMember as GameServer; - - if (server.ServerSettings.BotSpawnMode == BotSpawnMode.Normal) + if (GameMain.Server.ServerSettings.BotSpawnMode == BotSpawnMode.Normal) { return Character.CharacterList .FindAll(c => c.TeamID == Character.TeamType.Team1 && c.AIController != null && c.Info != null && c.IsDead) @@ -29,14 +26,14 @@ namespace Barotrauma.Networking .ToList(); } - int currPlayerCount = server.ConnectedClients.Count(c => + int currPlayerCount = GameMain.Server.ConnectedClients.Count(c => c.InGame && - (!c.SpectateOnly || (!server.ServerSettings.AllowSpectating && server.OwnerConnection != c.Connection))); + (!c.SpectateOnly || (!GameMain.Server.ServerSettings.AllowSpectating && GameMain.Server.OwnerConnection != c.Connection))); var existingBots = Character.CharacterList .FindAll(c => c.TeamID == Character.TeamType.Team1 && c.AIController != null && c.Info != null); - int requiredBots = server.ServerSettings.BotCount - currPlayerCount; + int requiredBots = GameMain.Server.ServerSettings.BotCount - currPlayerCount; requiredBots -= existingBots.Count(b => !b.IsDead); List botsToRespawn = new List(); @@ -58,21 +55,19 @@ namespace Barotrauma.Networking partial void UpdateWaiting(float deltaTime) { - var server = networkMember as GameServer; - int characterToRespawnCount = GetClientsToRespawn().Count; - int totalCharacterCount = server.ConnectedClients.Count; + int totalCharacterCount = GameMain.Server.ConnectedClients.Count; /*if (server.Character != null) { totalCharacterCount++; if (server.Character.IsDead) characterToRespawnCount++; }*/ - bool startCountdown = (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * server.ServerSettings.MinRespawnRatio, 1.0f); + bool startCountdown = (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f); if (startCountdown != CountdownStarted) { CountdownStarted = startCountdown; - server.CreateEntityEvent(this); + GameMain.Server.CreateEntityEvent(this); } if (!CountdownStarted) return; @@ -80,7 +75,7 @@ namespace Barotrauma.Networking respawnTimer -= deltaTime; if (respawnTimer <= 0.0f) { - respawnTimer = server.ServerSettings.RespawnInterval; + respawnTimer = GameMain.Server.ServerSettings.RespawnInterval; DispatchShuttle(); } @@ -98,13 +93,10 @@ namespace Barotrauma.Networking partial void DispatchShuttle() { - var server = networkMember as GameServer; - if (server == null) return; - if (respawnShuttle != null) { state = State.Transporting; - server.CreateEntityEvent(this); + GameMain.Server.CreateEntityEvent(this); ResetShuttle(); @@ -124,17 +116,78 @@ namespace Barotrauma.Networking { state = State.Waiting; GameServer.Log("Respawning everyone in main sub.", ServerLog.MessageType.Spawning); - server.CreateEntityEvent(this); + GameMain.Server.CreateEntityEvent(this); RespawnCharacters(); } } + partial void UpdateReturningProjSpecific() + { + foreach (Door door in shuttleDoors) + { + if (door.IsOpen) door.TrySetState(false, false, true); + } + + var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == respawnShuttle && g.ConnectedWall != null); + shuttleGaps.ForEach(g => Spawner.AddToRemoveQueue(g)); + + var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == respawnShuttle && i.GetComponent() != null); + dockingPorts.ForEach(d => d.GetComponent().Undock()); + + //shuttle has returned if the path has been traversed or the shuttle is close enough to the exit + if (!CoroutineManager.IsCoroutineRunning("forcepos")) + { + if ((shuttleSteering?.SteeringPath != null && shuttleSteering.SteeringPath.Finished) + || (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight && + Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f)) + { + CoroutineManager.StopCoroutines("forcepos"); + CoroutineManager.StartCoroutine( + ForceShuttleToPos(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f), 100.0f), "forcepos"); + + } + } + + if (respawnShuttle.WorldPosition.Y > Level.Loaded.Size.Y || shuttleReturnTimer <= 0.0f) + { + CoroutineManager.StopCoroutines("forcepos"); + + ResetShuttle(); + + state = State.Waiting; + GameServer.Log("The respawn shuttle has left.", ServerLog.MessageType.Spawning); + GameMain.Server.CreateEntityEvent(this); + + respawnTimer = GameMain.Server.ServerSettings.RespawnInterval; + CountdownStarted = false; + } + } + + partial void UpdateTransportingProjSpecific(float deltaTime) + { + //if there are no living chracters inside, transporting can be stopped immediately + if (!Character.CharacterList.Any(c => c.Submarine == respawnShuttle && !c.IsDead)) + { + shuttleTransportTimer = 0.0f; + } + + if (shuttleTransportTimer <= 0.0f) + { + GameServer.Log("The respawn shuttle is leaving.", ServerLog.MessageType.ServerMessage); + state = State.Returning; + + GameMain.Server.CreateEntityEvent(this); + + CountdownStarted = false; + maxTransportTime = GameMain.Server.ServerSettings.MaxTransportTime; + shuttleReturnTimer = maxTransportTime; + shuttleTransportTimer = maxTransportTime; + } + } + partial void RespawnCharactersProjSpecific() { - var server = networkMember as GameServer; - if (server == null) return; - var respawnSub = respawnShuttle ?? Submarine.MainSub; var clients = GetClientsToRespawn(); @@ -150,7 +203,7 @@ namespace Barotrauma.Networking var botsToSpawn = GetBotsToRespawn(); characterInfos.AddRange(botsToSpawn); - server.AssignJobs(clients); + GameMain.Server.AssignJobs(clients); foreach (Client c in clients) { c.CharacterInfo.Job = new Job(c.AssignedJob); @@ -241,7 +294,6 @@ namespace Barotrauma.Networking item.Description = shuttleSpawnPoints[i].IdCardDesc; } } - } } } diff --git a/Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs b/Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs index ec80a70d9..178889ce4 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs @@ -236,8 +236,8 @@ namespace Barotrauma.Networking TraitorsEnabled = traitorsEnabled; GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled); - var botSpawnMode = BotSpawnMode.Fill; - Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Fill"), out botSpawnMode); + var botSpawnMode = BotSpawnMode.Normal; + Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Normal"), out botSpawnMode); BotSpawnMode = botSpawnMode; //"65-90", "97-122", "48-59" = upper and lower case english alphabet and numbers diff --git a/Barotrauma/BarotraumaShared/OpenALSoft_LICENSE b/Barotrauma/BarotraumaShared/OpenALSoft_LICENSE new file mode 100644 index 000000000..8d5d00006 --- /dev/null +++ b/Barotrauma/BarotraumaShared/OpenALSoft_LICENSE @@ -0,0 +1,437 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/Barotrauma/BarotraumaShared/SharedContent.projitems b/Barotrauma/BarotraumaShared/SharedContent.projitems index 4e8cb7f62..cc7685501 100644 --- a/Barotrauma/BarotraumaShared/SharedContent.projitems +++ b/Barotrauma/BarotraumaShared/SharedContent.projitems @@ -2306,11 +2306,16 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + - Never + PreserveNewest - Never @@ -3448,7 +3453,6 @@ PreserveNewest - Never PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs index 5add4a6b3..07e5b86a8 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/AITarget.cs @@ -22,6 +22,11 @@ namespace Barotrauma private float soundRange; private float sightRange; + + /// + /// How long does it take for the ai target to fade out if not kept alive. + /// + public float FadeOutTime { get; private set; } = 3; public float SoundRange { @@ -121,6 +126,7 @@ namespace Barotrauma MinSoundRange = element.GetAttributeFloat("minsoundrange", SoundRange); MaxSightRange = element.GetAttributeFloat("maxsightrange", SightRange); MaxSoundRange = element.GetAttributeFloat("maxsoundrange", SoundRange); + FadeOutTime = element.GetAttributeFloat("fadeouttime", FadeOutTime); SonarLabel = element.GetAttributeString("sonarlabel", ""); string typeString = element.GetAttributeString("type", "Any"); if (Enum.TryParse(typeString, out TargetType t)) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 3d04ce7ae..059634be8 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -435,7 +435,7 @@ namespace Barotrauma { if (gap.Submarine != Character.Submarine) { continue; } if (gap.Open < 1 || gap.IsRoomToRoom) { continue; } - var path = indoorSteering.PathFinder.FindPath(Character.SimPosition, gap.SimPosition); + var path = indoorSteering.PathFinder.FindPath(Character.SimPosition, gap.SimPosition, Character.Submarine); if (!path.Unreachable) { if (escapePoint != Vector2.Zero) @@ -1182,7 +1182,7 @@ namespace Barotrauma } else if (target.Entity != null) { - //skip the target if it's a room and the character is already inside a sub + // Ignore the target if it's a room and the character is already inside a sub if (character.CurrentHull != null && target.Entity is Hull) { continue; } Door door = null; @@ -1203,6 +1203,12 @@ namespace Barotrauma break; } } + + // Ignore the target if it's a decoy and the character is already inside a sub + if (character.CurrentHull != null && targetingTag == "decoy") + { + continue; + } } else if (target.Entity is Structure s) { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs index 633163ab7..72c150ed6 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/IndoorsSteeringManager.cs @@ -154,6 +154,7 @@ namespace Barotrauma currentTarget = target; Vector2 pos = host.SimPosition; + // TODO: remove this and handle differently? if (character != null && character.Submarine == null) { var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false); @@ -163,7 +164,7 @@ namespace Barotrauma } } - var newPath = pathFinder.FindPath(pos, target, "(Character: " + character.Name + ")"); + var newPath = pathFinder.FindPath(pos, target, character.Submarine, "(Character: " + character.Name + ")"); bool useNewPath = currentPath == null || needsNewPath; if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable) { @@ -448,7 +449,8 @@ namespace Barotrauma private float? GetNodePenalty(PathNode node, PathNode nextNode) { - if (character == null) { return 0.0f; } + if (character == null) { return 0.0f; } + if (nextNode.Waypoint.isObstructed) { return null; } float penalty = 0.0f; if (nextNode.Waypoint.ConnectedGap != null && nextNode.Waypoint.ConnectedGap.Open < 0.9f) { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs index 0a1ae5f75..f51799a7a 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjective.cs @@ -215,11 +215,12 @@ namespace Barotrauma protected virtual void OnCompleted() { - if (Completed != null) - { - Completed(); - Completed = null; - } + Completed?.Invoke(); + //if (Completed != null) + //{ + // Completed(); + // Completed = null; + //} } public virtual void Reset() { } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs index 980ca257d..8e5f15598 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -181,8 +181,7 @@ namespace Barotrauma { if (closeEnough) { - character.AIController.SteeringManager.Reset(); - character.AnimController.TargetDir = Target.WorldPosition.X > character.WorldPosition.X ? Direction.Right : Direction.Left; + OnCompleted(); } return false; } @@ -204,11 +203,6 @@ namespace Barotrauma } } } - if (isCompleted) - { - character.AIController.SteeringManager.Reset(); - character.AnimController.TargetDir = Target.WorldPosition.X > character.WorldPosition.X ? Direction.Right : Direction.Left; - } return isCompleted; } @@ -223,5 +217,15 @@ namespace Barotrauma float interactionDistance = Target is Item i ? i.InteractDistance * 0.9f : 0; CloseEnough = Math.Max(interactionDistance, CloseEnough); } + + protected override void OnCompleted() + { + character.AIController.SteeringManager.Reset(); + if (Target != null) + { + character.AnimController.TargetDir = Target.WorldPosition.X > character.WorldPosition.X ? Direction.Right : Direction.Left; + } + base.OnCompleted(); + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs index 95a7972a0..aeabd6331 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -156,7 +156,7 @@ namespace Barotrauma bool isRoomNameFound = currentTarget.DisplayName != null; errorMsg = "(Character " + character.Name + " idling, target " + (isRoomNameFound ? currentTarget.DisplayName : currentTarget.ToString()) + ")"; #endif - var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsg); + var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: errorMsg); PathSteering.SetPath(path); } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs index 202310ced..c481eaa39 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Order.cs @@ -173,7 +173,7 @@ namespace Barotrauma if (targetCharacterName == null) targetCharacterName = ""; if (targetRoomName == null) targetRoomName = ""; - string msg = TextManager.GetWithVariables(messageTag, new string[2] { "[name]", "[roomname]" }, new string[2] { targetCharacterName, targetRoomName }, new bool[2] { false, true }); + string msg = TextManager.GetWithVariables(messageTag, new string[2] { "[name]", "[roomname]" }, new string[2] { targetCharacterName, targetRoomName }, new bool[2] { false, true }, true); if (msg == null) return ""; return msg; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/PathFinder.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/PathFinder.cs index 967a0b9d8..9f589cf8f 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/PathFinder.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/PathFinder.cs @@ -157,13 +157,18 @@ namespace Barotrauma } } - public SteeringPath FindPath(Vector2 start, Vector2 end, string errorMsgStr = null) + public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null) { float closestDist = 0.0f; PathNode startNode = null; foreach (PathNode node in nodes) { Vector2 nodePos = node.Position; + if (hostSub != null) + { + Vector2 diff = hostSub.SimPosition - node.Waypoint.Submarine.SimPosition; + nodePos -= diff; + } float xDiff = Math.Abs(start.X - nodePos.X); float yDiff = Math.Abs(start.Y - nodePos.Y); @@ -185,7 +190,7 @@ namespace Barotrauma if (insideSubmarine) { var body = Submarine.PickBody( - start, node.Waypoint.SimPosition, null, + start, nodePos, null, Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionStairs); if (body != null) @@ -215,7 +220,11 @@ namespace Barotrauma foreach (PathNode node in nodes) { Vector2 nodePos = node.Position; - + if (hostSub != null) + { + Vector2 diff = hostSub.SimPosition - node.Waypoint.Submarine.SimPosition; + nodePos -= diff; + } float dist = Vector2.DistanceSquared(end, nodePos); if (insideSubmarine) { @@ -229,7 +238,7 @@ namespace Barotrauma //if searching for a path inside the sub, make sure the waypoint is visible if (insideSubmarine) { - var body = Submarine.PickBody(end, node.Waypoint.SimPosition, null, + var body = Submarine.PickBody(end, nodePos, null, Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionStairs ); if (body != null) @@ -237,7 +246,6 @@ namespace Barotrauma //if (body.UserData is Submarine) continue; if (body.UserData is Structure && !((Structure)body.UserData).IsPlatform) continue; if (body.UserData is Item && body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) continue; - } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index f53705889..1ee54d3a3 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -2030,6 +2030,11 @@ namespace Barotrauma //Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us! bool allowRagdoll = GameMain.NetworkMember != null ? GameMain.NetworkMember.ServerSettings.AllowRagdollButton : true; + bool tooFastToUnragdoll = AnimController.Collider.LinearVelocity.LengthSquared() > 1f; + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) + { + tooFastToUnragdoll = false; + } if (IsForceRagdolled) { IsRagdolled = IsForceRagdolled; @@ -2039,7 +2044,7 @@ namespace Barotrauma IsRagdolled = IsKeyDown(InputType.Ragdoll); } //Keep us ragdolled if we were forced or we're too speedy to unragdoll - else if (allowRagdoll && (!IsRagdolled || AnimController.Collider.LinearVelocity.LengthSquared() < 1f)) + else if (allowRagdoll && (!IsRagdolled || !tooFastToUnragdoll)) { if (ragdollingLockTimer > 0.0f) { @@ -2589,7 +2594,7 @@ namespace Barotrauma if (info != null) { info.Remove(); } #if CLIENT - GameMain.GameSession?.CrewManager?.RemoveCharacter(this); + GameMain.GameSession?.CrewManager?.KillCharacter(this); #endif CharacterList.Remove(this); diff --git a/Barotrauma/BarotraumaShared/Source/CoroutineManager.cs b/Barotrauma/BarotraumaShared/Source/CoroutineManager.cs index e31ffb9dc..701d6259b 100644 --- a/Barotrauma/BarotraumaShared/Source/CoroutineManager.cs +++ b/Barotrauma/BarotraumaShared/Source/CoroutineManager.cs @@ -89,6 +89,14 @@ namespace Barotrauma public static void StopCoroutines(string name) { + Coroutines.ForEach(c => + { + if (c.Name == name) + { + c.Thread?.Abort(); + c.Thread?.Join(); + } + }); Coroutines.RemoveAll(c => c.Name == name); } @@ -99,31 +107,42 @@ namespace Barotrauma public static void ExecuteCoroutineThread(CoroutineHandle handle) { - while (true) + try { - if (handle.Coroutine.Current != null) + while (true) { - WaitForSeconds wfs = handle.Coroutine.Current as WaitForSeconds; - if (wfs != null) + if (handle.Coroutine.Current != null) { - Thread.Sleep((int)(wfs.TotalTime * 1000)); - } - else - { - switch ((CoroutineStatus)handle.Coroutine.Current) + WaitForSeconds wfs = handle.Coroutine.Current as WaitForSeconds; + if (wfs != null) { - case CoroutineStatus.Success: - return; + Thread.Sleep((int)(wfs.TotalTime * 1000)); + } + else + { + switch ((CoroutineStatus)handle.Coroutine.Current) + { + case CoroutineStatus.Success: + return; - case CoroutineStatus.Failure: - DebugConsole.ThrowError("Coroutine \"" + handle.Name + "\" has failed"); - return; + case CoroutineStatus.Failure: + DebugConsole.ThrowError("Coroutine \"" + handle.Name + "\" has failed"); + return; + } } } - } - Thread.Yield(); - if (!handle.Coroutine.MoveNext()) return; + Thread.Yield(); + if (!handle.Coroutine.MoveNext()) return; + } + } + catch (ThreadAbortException tae) + { + //not an error, don't worry about it + } + catch (Exception e) + { + DebugConsole.ThrowError("Coroutine \"" + handle.Name + "\" has thrown an exception", e); } } diff --git a/Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs b/Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs index 6c65cee87..13e1429f2 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs @@ -112,6 +112,7 @@ namespace Barotrauma List positions = new List(); foreach (var allowedPosition in availablePositions) { + if (Level.Loaded.ExtraWalls.Any(w => w.Cells.Any(c => c.IsPointInside(allowedPosition.Position.ToVector2())))) { continue; } positions.Add(allowedPosition.Position.ToVector2()); } diff --git a/Barotrauma/BarotraumaShared/Source/FrameCounter.cs b/Barotrauma/BarotraumaShared/Source/FrameCounter.cs index 906746002..647d4c6d8 100644 --- a/Barotrauma/BarotraumaShared/Source/FrameCounter.cs +++ b/Barotrauma/BarotraumaShared/Source/FrameCounter.cs @@ -42,7 +42,7 @@ namespace Barotrauma public float GetAverageElapsedMillisecs(string identifier) { if (!avgTicksPerFrame.ContainsKey(identifier)) return 0.0f; - return avgTicksPerFrame[identifier] / TimeSpan.TicksPerMillisecond; + return avgTicksPerFrame[identifier] / (float)TimeSpan.TicksPerMillisecond; } public bool Update(double deltaTime) diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs index 3ddd11311..514256b4d 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/CampaignMode.cs @@ -98,7 +98,7 @@ namespace Barotrauma { if (item.GetComponent() != null) { - item.Condition = item.Health; + item.Condition = item.Prefab.Health; } } } @@ -176,7 +176,16 @@ namespace Barotrauma Level.Loaded.Seed + (outpost == Level.Loaded.StartOutpost ? "start" : "end")); InitializeWatchman(spawnedCharacter); var objectiveManager = (spawnedCharacter.AIController as HumanAIController)?.ObjectiveManager; - objectiveManager?.SetOrder(new AIObjectiveGoTo(watchmanSpawnpoint, spawnedCharacter, objectiveManager, repeat: true, getDivingGearIfNeeded: false)); + if (objectiveManager != null) + { + var moveOrder = new AIObjectiveGoTo(watchmanSpawnpoint, spawnedCharacter, objectiveManager, repeat: true, getDivingGearIfNeeded: false); + moveOrder.Completed += () => + { + // Turn towards the center of the sub. Doesn't work in all possible cases, but this is the simplest solution for now. + spawnedCharacter.AnimController.TargetDir = spawnedCharacter.Submarine.WorldPosition.X > spawnedCharacter.WorldPosition.X ? Direction.Right : Direction.Left; + }; + objectiveManager.SetOrder(moveOrder); + } if (watchmanJob != null) { spawnedCharacter.GiveJobItems(); diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index 32e255691..30bf32cab 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -241,6 +241,14 @@ namespace Barotrauma } } + foreach (var sub in Submarine.Loaded) + { + if (sub.IsOutpost) + { + sub.DisableObstructedWayPoints(); + } + } + Entity.Spawner = new EntitySpawner(); if (GameMode.Mission != null) Mission = GameMode.Mission; diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index 26313251a..79f5a57c6 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -25,7 +25,7 @@ namespace Barotrauma } public partial class GameSettings - { + { const string savePath = "config.xml"; const string playerSavePath = "config_player.xml"; const string vanillaContentPackagePath = "Data/ContentPackages/Vanilla"; @@ -43,9 +43,9 @@ namespace Barotrauma public bool SpecularityEnabled { get; set; } public bool ChromaticAberrationEnabled { get; set; } - public bool PauseOnFocusLost { get; set; } = true; + public bool PauseOnFocusLost { get; set; } public bool MuteOnFocusLost { get; set; } - public bool UseDirectionalVoiceChat { get; set; } = true; + public bool UseDirectionalVoiceChat { get; set; } public enum VoiceMode { @@ -57,7 +57,7 @@ namespace Barotrauma public VoiceMode VoiceSetting { get; set; } public string VoiceCaptureDevice { get; set; } - public float NoiseGateThreshold { get; set; } = -45; + public float NoiseGateThreshold { get; set; } private KeyOrMouse[] keyMapping; @@ -69,12 +69,7 @@ namespace Barotrauma private bool useSteamMatchmaking; private bool requireSteamAuthentication; - - public string QuickStartSubmarineName - { - get; - set; - } + public string QuickStartSubmarineName; #if DEBUG //steam functionality can be enabled/disabled in debug builds @@ -126,7 +121,7 @@ namespace Barotrauma set { jobPreferences = value; } } - public int CharacterHeadIndex { get; set; } = 1; + public int CharacterHeadIndex { get; set; } public int CharacterHairIndex { get; set; } public int CharacterBeardIndex { get; set; } public int CharacterMoustacheIndex { get; set; } @@ -160,7 +155,6 @@ namespace Barotrauma #if CLIENT if (applyButton != null) { - //applyButton.Selected = unsavedSettings; applyButton.Enabled = unsavedSettings; applyButton.Text = TextManager.Get(unsavedSettings ? "ApplySettingsButtonUnsavedChanges" : "ApplySettingsButton"); } @@ -168,7 +162,7 @@ namespace Barotrauma } } - private float soundVolume = 0.5f, musicVolume = 0.3f, voiceChatVolume = 0.5f, microphoneVolume = 1.0f; + private float soundVolume, musicVolume, voiceChatVolume, microphoneVolume; public float SoundVolume { @@ -229,9 +223,9 @@ namespace Barotrauma private HashSet selectedContentPackagePaths = new HashSet(); - public string MasterServerUrl { get; set; } - public bool AutoCheckUpdates { get; set; } - public bool WasGameUpdated { get; set; } + public string MasterServerUrl { get; set; } + public bool AutoCheckUpdates { get; set; } + public bool WasGameUpdated { get; set; } private string defaultPlayerName; public string DefaultPlayerName @@ -256,9 +250,9 @@ namespace Barotrauma } private const float MinHUDScale = 0.75f, MaxHUDScale = 1.25f; - public static float HUDScale { get; set; } = 1.0f; + public static float HUDScale { get; set; } private const float MinInventoryScale = 0.75f, MaxInventoryScale = 1.25f; - public static float InventoryScale { get; set; } = 1.0f; + public static float InventoryScale { get; set; } public List CompletedTutorialNames { get; private set; } @@ -267,7 +261,7 @@ namespace Barotrauma public bool CampaignDisclaimerShown, EditorDisclaimerShown; - private static bool sendUserStatistics; + private static bool sendUserStatistics = true; public static bool SendUserStatistics { get { return sendUserStatistics; } @@ -353,13 +347,7 @@ namespace Barotrauma } if (doc != null) { - foreach (XElement subElement in doc.Root.Elements()) - { - if (subElement.Name.ToString().ToLowerInvariant() == "keymapping") - { - LoadKeyBinds(subElement); - } - } + LoadControls(doc); } } @@ -415,35 +403,15 @@ namespace Barotrauma } } - #region Load DefaultConfig private void LoadDefaultConfig(bool setLanguage = true) { XDocument doc = XMLExtensions.TryLoadXml(savePath); - - if (setLanguage || string.IsNullOrEmpty(Language)) - { - Language = doc.Root.GetAttributeString("language", "English"); - } - - MasterServerUrl = doc.Root.GetAttributeString("masterserverurl", ""); - - AutoCheckUpdates = doc.Root.GetAttributeBool("autocheckupdates", true); - WasGameUpdated = doc.Root.GetAttributeBool("wasgameupdated", false); - - VerboseLogging = doc.Root.GetAttributeBool("verboselogging", false); - SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", false); - - QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsub", ""); - if (doc == null) { GraphicsWidth = 1024; - GraphicsHeight = 678; - + GraphicsHeight = 768; MasterServerUrl = ""; - SelectedContentPackages.Add(ContentPackage.List.Any() ? ContentPackage.List[0] : new ContentPackage("")); - jobPreferences = new List(); foreach (JobPrefab job in JobPrefab.List) { @@ -452,158 +420,24 @@ namespace Barotrauma return; } - XElement graphicsMode = doc.Root.Element("graphicsmode"); - GraphicsWidth = 0; - GraphicsHeight = 0; - VSyncEnabled = graphicsMode.GetAttributeBool("vsync", true); - - XElement graphicsSettings = doc.Root.Element("graphicssettings"); - ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", 1500); - LightMapScale = MathHelper.Clamp(graphicsSettings.GetAttributeFloat("lightmapscale", 0.5f), 0.1f, 1.0f); - SpecularityEnabled = graphicsSettings.GetAttributeBool("specularity", true); - ChromaticAberrationEnabled = graphicsSettings.GetAttributeBool("chromaticaberration", true); - HUDScale = graphicsSettings.GetAttributeFloat("hudscale", 1.0f); - InventoryScale = graphicsSettings.GetAttributeFloat("inventoryscale", 1.0f); - var losModeStr = graphicsSettings.GetAttributeString("losmode", "Transparent"); - if (!Enum.TryParse(losModeStr, out losMode)) - { - losMode = LosMode.Transparent; - } - -#if CLIENT - if (GraphicsWidth == 0 || GraphicsHeight == 0) - { - GraphicsWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width; - GraphicsHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height; - } -#endif - - var windowModeStr = graphicsMode.GetAttributeString("displaymode", "Fullscreen"); - if (!Enum.TryParse(windowModeStr, out WindowMode wm)) - { - wm = WindowMode.Fullscreen; - } - WindowMode = wm; - - useSteamMatchmaking = doc.Root.GetAttributeBool("usesteammatchmaking", true); - requireSteamAuthentication = doc.Root.GetAttributeBool("requiresteamauthentication", true); - AutoUpdateWorkshopItems = doc.Root.GetAttributeBool("autoupdateworkshopitems", true); - -#if DEBUG - EnableSplashScreen = false; -#else - EnableSplashScreen = doc.Root.GetAttributeBool("enablesplashscreen", true); -#endif - - AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f); - + bool resetLanguage = setLanguage || string.IsNullOrEmpty(Language); + SetDefaultValues(resetLanguage); SetDefaultBindings(doc, legacy: false); - foreach (XElement subElement in doc.Root.Elements()) - { - switch (subElement.Name.ToString().ToLowerInvariant()) - { - case "keymapping": - LoadKeyBinds(subElement); - break; - case "gameplay": - jobPreferences = new List(); - foreach (XElement ele in subElement.Element("jobpreferences").Elements("job")) - { - string jobIdentifier = ele.GetAttributeString("identifier", ""); - if (string.IsNullOrEmpty(jobIdentifier)) continue; - jobPreferences.Add(jobIdentifier); - } - break; - case "player": - defaultPlayerName = subElement.GetAttributeString("name", ""); - CharacterHeadIndex = subElement.GetAttributeInt("headindex", CharacterHeadIndex); - if (Enum.TryParse(subElement.GetAttributeString("gender", "none"), true, out Gender g)) - { - CharacterGender = g; - } - if (Enum.TryParse(subElement.GetAttributeString("race", "white"), true, out Race r)) - { - CharacterRace = r; - } - else - { - CharacterRace = Race.White; - } - CharacterHairIndex = subElement.GetAttributeInt("hairindex", -1); - CharacterBeardIndex = subElement.GetAttributeInt("beardindex", -1); - CharacterMoustacheIndex = subElement.GetAttributeInt("moustacheindex", -1); - CharacterFaceAttachmentIndex = subElement.GetAttributeInt("faceattachmentindex", -1); - break; - } - } + MasterServerUrl = doc.Root.GetAttributeString("masterserverurl", MasterServerUrl); + WasGameUpdated = doc.Root.GetAttributeBool("wasgameupdated", WasGameUpdated); + VerboseLogging = doc.Root.GetAttributeBool("verboselogging", VerboseLogging); + SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", SaveDebugConsoleLogs); + AutoUpdateWorkshopItems = doc.Root.GetAttributeBool("autoupdateworkshopitems", AutoUpdateWorkshopItems); - List missingPackagePaths = new List(); - List incompatiblePackages = new List(); - foreach (XElement subElement in doc.Root.Elements()) - { - switch (subElement.Name.ToString().ToLowerInvariant()) - { - case "contentpackage": - string path = System.IO.Path.GetFullPath(subElement.GetAttributeString("path", "")); - var matchingContentPackage = ContentPackage.List.Find(cp => System.IO.Path.GetFullPath(cp.Path) == path); - if (matchingContentPackage == null) - { - missingPackagePaths.Add(path); - } - else if (!matchingContentPackage.IsCompatible()) - { - incompatiblePackages.Add(matchingContentPackage); - } - else - { - SelectedContentPackages.Add(matchingContentPackage); - } - break; - } - } - - TextManager.LoadTextPacks(SelectedContentPackages); - - //display error messages after all content packages have been loaded - //to make sure the package that contains text files has been loaded before we attempt to use TextManager - foreach (string missingPackagePath in missingPackagePaths) - { - DebugConsole.ThrowError(TextManager.GetWithVariable("ContentPackageNotFound", "[packagepath]", missingPackagePath)); - } - foreach (ContentPackage incompatiblePackage in incompatiblePackages) - { - DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage", - new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() })); - } - foreach (ContentPackage contentPackage in SelectedContentPackages) - { - bool packageOk = contentPackage.VerifyFiles(out List errorMessages); - if (!packageOk) - { - DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\":\n" + string.Join("\n", errorMessages)); - continue; - } - foreach (ContentFile file in contentPackage.Files) - { - ToolBox.IsProperFilenameCase(file.Path); - } - } - if (!SelectedContentPackages.Any()) - { - var availablePackage = ContentPackage.List.FirstOrDefault(cp => cp.IsCompatible() && cp.CorePackage); - if (availablePackage != null) - { - SelectedContentPackages.Add(availablePackage); - } - } - - //save to get rid of the invalid selected packages in the config file - if (missingPackagePaths.Count > 0 || incompatiblePackages.Count > 0) { SaveNewPlayerConfig(); } + LoadGeneralSettings(doc, resetLanguage); + LoadGraphicSettings(doc); + LoadAudioSettings(doc); + LoadControls(doc); + LoadContentPackages(doc); + UnsavedSettings = false; } - #endregion - #region Save DefaultConfig private void SaveNewDefaultConfig() { XDocument doc = new XDocument(); @@ -619,6 +453,7 @@ namespace Barotrauma new XAttribute("autocheckupdates", AutoCheckUpdates), new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), + new XAttribute("microphonevolume", microphoneVolume), new XAttribute("voicechatvolume", voiceChatVolume), new XAttribute("verboselogging", VerboseLogging), new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs), @@ -637,7 +472,7 @@ namespace Barotrauma { doc.Root.Add(new XAttribute("wasgameupdated", true)); } - + XElement gMode = doc.Root.Element("graphicsmode"); if (gMode == null) { @@ -738,7 +573,6 @@ namespace Barotrauma "Saving game settings failed.\n" + e.Message + "\n" + e.StackTrace); } } - #endregion #region Load PlayerConfig public void LoadPlayerConfig() @@ -760,143 +594,27 @@ namespace Barotrauma private bool LoadPlayerConfigInternal() { XDocument doc = XMLExtensions.LoadXml(playerSavePath); - if (doc == null || doc.Root == null) { ShowUserStatisticsPrompt = true; return false; } + LoadGeneralSettings(doc); + LoadGraphicSettings(doc); + LoadAudioSettings(doc); + LoadControls(doc); + LoadContentPackages(doc); - Language = doc.Root.GetAttributeString("language", Language); - AutoCheckUpdates = doc.Root.GetAttributeBool("autocheckupdates", AutoCheckUpdates); - sendUserStatistics = doc.Root.GetAttributeBool("senduserstatistics", true); - - XElement graphicsMode = doc.Root.Element("graphicsmode"); - GraphicsWidth = graphicsMode.GetAttributeInt("width", GraphicsWidth); - GraphicsHeight = graphicsMode.GetAttributeInt("height", GraphicsHeight); - VSyncEnabled = graphicsMode.GetAttributeBool("vsync", VSyncEnabled); - - XElement graphicsSettings = doc.Root.Element("graphicssettings"); - ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", ParticleLimit); - LightMapScale = MathHelper.Clamp(graphicsSettings.GetAttributeFloat("lightmapscale", LightMapScale), 0.1f, 1.0f); - SpecularityEnabled = graphicsSettings.GetAttributeBool("specularity", SpecularityEnabled); - ChromaticAberrationEnabled = graphicsSettings.GetAttributeBool("chromaticaberration", ChromaticAberrationEnabled); - HUDScale = graphicsSettings.GetAttributeFloat("hudscale", HUDScale); - InventoryScale = graphicsSettings.GetAttributeFloat("inventoryscale", InventoryScale); - var losModeStr = graphicsSettings.GetAttributeString("losmode", "Transparent"); - if (!Enum.TryParse(losModeStr, out losMode)) + XElement tutorialsElement = doc.Root.Element("tutorials"); + if (tutorialsElement != null) { - losMode = LosMode.Transparent; - } - -#if CLIENT - if (GraphicsWidth == 0 || GraphicsHeight == 0) - { - GraphicsWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width; - GraphicsHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height; - } -#endif - - var windowModeStr = graphicsMode.GetAttributeString("displaymode", "Fullscreen"); - if (!Enum.TryParse(windowModeStr, out windowMode)) - { - windowMode = WindowMode.Fullscreen; - } - - XElement audioSettings = doc.Root.Element("audio"); - if (audioSettings != null) - { - SoundVolume = audioSettings.GetAttributeFloat("soundvolume", SoundVolume); - MusicVolume = audioSettings.GetAttributeFloat("musicvolume", MusicVolume); - VoiceChatVolume = audioSettings.GetAttributeFloat("voicechatvolume", VoiceChatVolume); - MuteOnFocusLost = audioSettings.GetAttributeBool("muteonfocuslost", false); - UseDirectionalVoiceChat = audioSettings.GetAttributeBool("usedirectionalvoicechat", true); - string voiceSettingStr = audioSettings.GetAttributeString("voicesetting", "Disabled"); - VoiceCaptureDevice = audioSettings.GetAttributeString("voicecapturedevice", ""); - NoiseGateThreshold = audioSettings.GetAttributeFloat("noisegatethreshold", -45); - var voiceSetting = VoiceMode.Disabled; - if (Enum.TryParse(voiceSettingStr, out voiceSetting)) + foreach (XElement element in tutorialsElement.Elements()) { - VoiceSetting = voiceSetting; - } - } - - useSteamMatchmaking = doc.Root.GetAttributeBool("usesteammatchmaking", useSteamMatchmaking); - requireSteamAuthentication = doc.Root.GetAttributeBool("requiresteamauthentication", requireSteamAuthentication); - - EnableSplashScreen = doc.Root.GetAttributeBool("enablesplashscreen", EnableSplashScreen); - - PauseOnFocusLost = doc.Root.GetAttributeBool("pauseonfocuslost", PauseOnFocusLost); - AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", AimAssistAmount); - EnableMouseLook = doc.Root.GetAttributeBool("enablemouselook", EnableMouseLook); - - CrewMenuOpen = doc.Root.GetAttributeBool("crewmenuopen", CrewMenuOpen); - ChatOpen = doc.Root.GetAttributeBool("chatopen", ChatOpen); - - CampaignDisclaimerShown = doc.Root.GetAttributeBool("campaigndisclaimershown", false); - EditorDisclaimerShown = doc.Root.GetAttributeBool("editordisclaimershown", false); - - foreach (XElement subElement in doc.Root.Elements()) - { - switch (subElement.Name.ToString().ToLowerInvariant()) - { - case "keymapping": - LoadKeyBinds(subElement); - break; - case "gameplay": - jobPreferences = new List(); - foreach (XElement ele in subElement.Element("jobpreferences").Elements("job")) - { - string jobIdentifier = ele.GetAttributeString("identifier", ""); - if (string.IsNullOrEmpty(jobIdentifier)) continue; - jobPreferences.Add(jobIdentifier); - } - break; - case "player": - defaultPlayerName = subElement.GetAttributeString("name", defaultPlayerName); - CharacterHeadIndex = subElement.GetAttributeInt("headindex", CharacterHeadIndex); - if (Enum.TryParse(subElement.GetAttributeString("gender", "none"), true, out Gender g)) - { - CharacterGender = g; - } - if (Enum.TryParse(subElement.GetAttributeString("race", "white"), true, out Race r)) - { - CharacterRace = r; - } - else - { - CharacterRace = Race.White; - } - CharacterHairIndex = subElement.GetAttributeInt("hairindex", CharacterHairIndex); - CharacterBeardIndex = subElement.GetAttributeInt("beardindex", CharacterBeardIndex); - CharacterMoustacheIndex = subElement.GetAttributeInt("moustacheindex", CharacterMoustacheIndex); - CharacterFaceAttachmentIndex = subElement.GetAttributeInt("faceattachmentindex", CharacterFaceAttachmentIndex); - break; - case "tutorials": - foreach (XElement tutorialElement in subElement.Elements()) - { - CompletedTutorialNames.Add(tutorialElement.GetAttributeString("name", "")); - } - break; + CompletedTutorialNames.Add(element.GetAttributeString("name", "")); } } UnsavedSettings = false; - - selectedContentPackagePaths = new HashSet(); - - foreach (XElement subElement in doc.Root.Elements()) - { - switch (subElement.Name.ToString().ToLowerInvariant()) - { - case "contentpackage": - string path = System.IO.Path.GetFullPath(subElement.GetAttributeString("path", "")); - selectedContentPackagePaths.Add(path); - break; - } - } - - LoadContentPackages(selectedContentPackagePaths); return true; } @@ -957,7 +675,7 @@ namespace Barotrauma } foreach (ContentPackage incompatiblePackage in incompatiblePackages) { - DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage", + DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage", new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() })); } } @@ -1038,7 +756,7 @@ namespace Barotrauma new XAttribute("vsync", VSyncEnabled), new XAttribute("displaymode", windowMode)); } - + XElement audio = doc.Root.Element("audio"); if (audio == null) { @@ -1048,6 +766,8 @@ namespace Barotrauma audio.ReplaceAttributes( new XAttribute("musicvolume", musicVolume), new XAttribute("soundvolume", soundVolume), + new XAttribute("voicechatvolume", voiceChatVolume), + new XAttribute("microphonevolume", microphoneVolume), new XAttribute("muteonfocuslost", MuteOnFocusLost), new XAttribute("usedirectionalvoicechat", UseDirectionalVoiceChat), new XAttribute("voicesetting", VoiceSetting), @@ -1153,12 +873,149 @@ namespace Barotrauma } #endregion + #region Loading Configs + private void LoadGeneralSettings(XDocument doc, bool setLanguage = true) + { + if (setLanguage) + { + Language = doc.Root.GetAttributeString("language", Language); + } + AutoCheckUpdates = doc.Root.GetAttributeBool("autocheckupdates", AutoCheckUpdates); + sendUserStatistics = doc.Root.GetAttributeBool("senduserstatistics", sendUserStatistics); + QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsubmarine", ""); + useSteamMatchmaking = doc.Root.GetAttributeBool("usesteammatchmaking", useSteamMatchmaking); + requireSteamAuthentication = doc.Root.GetAttributeBool("requiresteamauthentication", requireSteamAuthentication); + EnableSplashScreen = doc.Root.GetAttributeBool("enablesplashscreen", EnableSplashScreen); + PauseOnFocusLost = doc.Root.GetAttributeBool("pauseonfocuslost", PauseOnFocusLost); + AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", AimAssistAmount); + EnableMouseLook = doc.Root.GetAttributeBool("enablemouselook", EnableMouseLook); + CrewMenuOpen = doc.Root.GetAttributeBool("crewmenuopen", CrewMenuOpen); + ChatOpen = doc.Root.GetAttributeBool("chatopen", ChatOpen); + CampaignDisclaimerShown = doc.Root.GetAttributeBool("campaigndisclaimershown", CampaignDisclaimerShown); + EditorDisclaimerShown = doc.Root.GetAttributeBool("editordisclaimershown", EditorDisclaimerShown); + XElement gameplayElement = doc.Root.Element("gameplay"); + if (gameplayElement != null) + { + jobPreferences = new List(); + foreach (XElement ele in gameplayElement.Element("jobpreferences").Elements("job")) + { + string jobIdentifier = ele.GetAttributeString("identifier", ""); + if (string.IsNullOrEmpty(jobIdentifier)) continue; + jobPreferences.Add(jobIdentifier); + } + } + + XElement playerElement = doc.Root.Element("player"); + if (playerElement != null) + { + defaultPlayerName = playerElement.GetAttributeString("name", defaultPlayerName); + CharacterHeadIndex = playerElement.GetAttributeInt("headindex", CharacterHeadIndex); + if (Enum.TryParse(playerElement.GetAttributeString("gender", "none"), true, out Gender g)) + { + CharacterGender = g; + } + if (Enum.TryParse(playerElement.GetAttributeString("race", "white"), true, out Race r)) + { + CharacterRace = r; + } + else + { + CharacterRace = Race.White; + } + CharacterHairIndex = playerElement.GetAttributeInt("hairindex", CharacterHairIndex); + CharacterBeardIndex = playerElement.GetAttributeInt("beardindex", CharacterBeardIndex); + CharacterMoustacheIndex = playerElement.GetAttributeInt("moustacheindex", CharacterMoustacheIndex); + CharacterFaceAttachmentIndex = playerElement.GetAttributeInt("faceattachmentindex", CharacterFaceAttachmentIndex); + } + } + + private void LoadGraphicSettings(XDocument doc) + { + XElement graphicsMode = doc.Root.Element("graphicsmode"); + GraphicsWidth = graphicsMode.GetAttributeInt("width", GraphicsWidth); + GraphicsHeight = graphicsMode.GetAttributeInt("height", GraphicsHeight); + VSyncEnabled = graphicsMode.GetAttributeBool("vsync", VSyncEnabled); + + XElement graphicsSettings = doc.Root.Element("graphicssettings"); + ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", ParticleLimit); + LightMapScale = MathHelper.Clamp(graphicsSettings.GetAttributeFloat("lightmapscale", LightMapScale), 0.1f, 1.0f); + SpecularityEnabled = graphicsSettings.GetAttributeBool("specularity", SpecularityEnabled); + ChromaticAberrationEnabled = graphicsSettings.GetAttributeBool("chromaticaberration", ChromaticAberrationEnabled); + HUDScale = graphicsSettings.GetAttributeFloat("hudscale", HUDScale); + InventoryScale = graphicsSettings.GetAttributeFloat("inventoryscale", InventoryScale); + var losModeStr = graphicsSettings.GetAttributeString("losmode", "Transparent"); + if (!Enum.TryParse(losModeStr, out losMode)) + { + losMode = LosMode.Transparent; + } +#if CLIENT + if (GraphicsWidth == 0 || GraphicsHeight == 0) + { + GraphicsWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width; + GraphicsHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height; + } +#endif + var windowModeStr = graphicsMode.GetAttributeString("displaymode", "Fullscreen"); + if (!Enum.TryParse(windowModeStr, out windowMode)) + { + windowMode = WindowMode.Fullscreen; + } + } + + private void LoadAudioSettings(XDocument doc) + { + XElement audioSettings = doc.Root.Element("audio"); + if (audioSettings != null) + { + SoundVolume = audioSettings.GetAttributeFloat("soundvolume", SoundVolume); + MusicVolume = audioSettings.GetAttributeFloat("musicvolume", MusicVolume); + VoiceChatVolume = audioSettings.GetAttributeFloat("voicechatvolume", VoiceChatVolume); + MuteOnFocusLost = audioSettings.GetAttributeBool("muteonfocuslost", MuteOnFocusLost); + UseDirectionalVoiceChat = audioSettings.GetAttributeBool("usedirectionalvoicechat", UseDirectionalVoiceChat); + VoiceCaptureDevice = audioSettings.GetAttributeString("voicecapturedevice", VoiceCaptureDevice); + NoiseGateThreshold = audioSettings.GetAttributeFloat("noisegatethreshold", NoiseGateThreshold); + MicrophoneVolume = audioSettings.GetAttributeFloat("microphonevolume", MicrophoneVolume); + var voiceSetting = VoiceMode.Disabled; + string voiceSettingStr = audioSettings.GetAttributeString("voicesetting", ""); + if (Enum.TryParse(voiceSettingStr, out voiceSetting)) + { + VoiceSetting = voiceSetting; + } + } + } + + private void LoadControls(XDocument doc) + { + XElement keyMapping = doc.Root.Element("keymapping"); + if (keyMapping != null) + { + LoadKeyBinds(keyMapping); + } + } + + private void LoadContentPackages(XDocument doc) + { + selectedContentPackagePaths = new HashSet(); + foreach (XElement subElement in doc.Root.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "contentpackage": + string path = System.IO.Path.GetFullPath(subElement.GetAttributeString("path", "")); + selectedContentPackagePaths.Add(path); + break; + } + } + LoadContentPackages(selectedContentPackagePaths); + } + #endregion + private void LoadKeyBinds(XElement element) { foreach (XAttribute attribute in element.Attributes()) { if (!Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType)) { continue; } - + if (int.TryParse(attribute.Value.ToString(), out int mouseButton)) { keyMapping[(int)inputType] = new KeyOrMouse(mouseButton); @@ -1169,7 +1026,7 @@ namespace Barotrauma { keyMapping[(int)inputType] = new KeyOrMouse(key); } - } + } } } @@ -1184,5 +1041,62 @@ namespace Barotrauma { return keyMapping[(int)inputType]; } + + private void SetDefaultValues(bool resetLanguage = true) + { + GraphicsWidth = 0; + GraphicsHeight = 0; + VSyncEnabled = true; +#if DEBUG + EnableSplashScreen = false; +#else + EnableSplashScreen = true; +#endif + ParticleLimit = 1500; + LightMapScale = 0.5f; + SpecularityEnabled = false; + ChromaticAberrationEnabled = true; + PauseOnFocusLost = true; + MuteOnFocusLost = false; + UseDirectionalVoiceChat = true; + VoiceSetting = VoiceMode.Disabled; + VoiceCaptureDevice = null; + NoiseGateThreshold = -45; + windowMode = WindowMode.Fullscreen; + losMode = LosMode.Transparent; + useSteamMatchmaking = true; + requireSteamAuthentication = true; + QuickStartSubmarineName = string.Empty; + CharacterHeadIndex = 1; + CharacterHairIndex = -1; + CharacterBeardIndex = -1; + CharacterMoustacheIndex = -1; + CharacterFaceAttachmentIndex = -1; + CharacterGender = Gender.None; + CharacterRace = Race.White; + aimAssistAmount = 0.5f; + EnableMouseLook = true; + CrewMenuOpen = true; + ChatOpen = true; + soundVolume = 0.5f; + musicVolume = 0.3f; + voiceChatVolume = 0.5f; + microphoneVolume = 1.0f; + AutoCheckUpdates = true; + defaultPlayerName = string.Empty; + HUDScale = 1; + InventoryScale = 1; + AutoUpdateWorkshopItems = true; + CampaignDisclaimerShown = false; + if (resetLanguage) + { + Language = "English"; + } + MasterServerUrl = "http://www.undertowgames.com/baromaster"; + WasGameUpdated = false; + VerboseLogging = false; + SaveDebugConsoleLogs = false; + AutoUpdateWorkshopItems = true; + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs index 51ffb733b..5ff19891e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/DockingPort.cs @@ -33,6 +33,7 @@ namespace Barotrauma.Items.Components private Body doorBody; private bool docked; + private bool obstructedWayPointsDisabled; private float forceLockTimer; //if the submarine isn't in the correct position to lock within this time after docking has been activated, @@ -732,6 +733,9 @@ namespace Barotrauma.Items.Components bodies = null; } + Item.Submarine.EnableObstructedWaypoints(); + obstructedWayPointsDisabled = false; + #if SERVER if (GameMain.Server != null) { @@ -813,6 +817,11 @@ namespace Barotrauma.Items.Components dockingState = MathHelper.Lerp(dockingState, 1.0f, deltaTime * 10.0f); } } + if (!obstructedWayPointsDisabled && dockingState >= 0.99f) + { + Item.Submarine.DisableObstructedWayPoints(DockingTarget?.Item.Submarine); + obstructedWayPointsDisabled = true; + } } protected override void RemoveComponentSpecific() @@ -983,6 +992,5 @@ namespace Barotrauma.Items.Components Undock(); } } - } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs index 4250a83ab..c375e83fa 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs @@ -413,7 +413,7 @@ namespace Barotrauma.Items.Components { target = ConvertUnits.ToSimUnits(Level.Loaded.StartPosition); } - steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition), target, "(Autopilot, target: " + target + ")"); + steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition), target, errorMsgStr: "(Autopilot, target: " + target + ")"); } public void SetDestinationLevelStart() diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index f821873bc..12375fecf 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -174,6 +174,12 @@ namespace Barotrauma.Items.Components private void Launch(Vector2 impulse) { + if (item.AiTarget != null) + { + item.AiTarget.SightRange = item.AiTarget.MaxSightRange; + item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange; + } + item.Drop(null); item.body.Enabled = true; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Repairable.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Repairable.cs index a81376338..a17399612 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Repairable.cs @@ -122,6 +122,16 @@ namespace Barotrauma.Items.Components Update(deltaTime, cam); } + public void ResetDeterioration() + { + deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay); + item.Condition = item.Prefab.Health; +#if SERVER + //let the clients know the initial deterioration delay + item.CreateServerEvent(this); +#endif + } + public override void Update(float deltaTime, Camera cam) { UpdateProjSpecific(deltaTime); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs index 0d76efa20..c26ed06c5 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs @@ -338,9 +338,15 @@ namespace Barotrauma.Items.Components canPlaceNode = true; } + Vector2 relativeNodePos = newNodePos - item.Position; + if (sub != null) + { + relativeNodePos += sub.HiddenSubPosition; + } + sectionExtents = new Vector2( - Math.Max(Math.Abs((newNodePos.X + sub.HiddenSubPosition.X) - item.Position.X), sectionExtents.X), - Math.Max(Math.Abs((newNodePos.Y + sub.HiddenSubPosition.Y) - item.Position.Y), sectionExtents.Y)); + Math.Max(Math.Abs(relativeNodePos.X), sectionExtents.X), + Math.Max(Math.Abs(relativeNodePos.Y), sectionExtents.Y)); } public override bool Use(float deltaTime, Character character = null) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs index 1befb10a5..974b41790 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs @@ -286,6 +286,23 @@ namespace Barotrauma.Items.Components if (!equipLimb.WearingItems.Contains(wearableSprite)) { equipLimb.WearingItems.Add(wearableSprite); + equipLimb.WearingItems.Sort((i1, i2) => { return i2.Sprite.Depth.CompareTo(i1.Sprite.Depth); }); + equipLimb.WearingItems.Sort((i1, i2) => + { + if (i1?.WearableComponent == null && i2?.WearableComponent == null) + { + return 0; + } + else if (i1?.WearableComponent == null) + { + return -1; + } + else if (i2?.WearableComponent == null) + { + return 1; + } + return i1.WearableComponent.AllowedSlots.Contains(InvSlotType.OuterClothes).CompareTo(i2.WearableComponent.AllowedSlots.Contains(InvSlotType.OuterClothes)); + }); } } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 752d3df85..9f66bfd6e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1042,8 +1042,8 @@ namespace Barotrauma //aitarget goes silent/invisible if the components don't keep it active if (aiTarget != null) { - aiTarget.SightRange -= deltaTime * 1000.0f; - aiTarget.SoundRange -= deltaTime * 1000.0f; + aiTarget.SightRange -= deltaTime * (aiTarget.MaxSightRange / aiTarget.FadeOutTime); + aiTarget.SoundRange -= deltaTime * (aiTarget.MaxSoundRange / aiTarget.FadeOutTime); } bool broken = condition <= 0.0f; @@ -2017,6 +2017,8 @@ namespace Barotrauma if (element.GetAttributeBool("flippedy", false)) item.FlipY(false); item.condition = element.GetAttributeFloat("condition", item.Prefab.Health); + item.lastSentCondition = item.condition; + item.SetActiveSprite(); foreach (ItemComponent component in item.components) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs index 68b5ca6df..41b29c95a 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs @@ -1366,6 +1366,11 @@ namespace Barotrauma } List suitablePositions = positionsOfInterest.FindAll(p => positionType.HasFlag(p.PositionType)); + //avoid floating ice chunks on the main path + if (positionType == PositionType.MainPath) + { + suitablePositions.RemoveAll(p => extraWalls.Any(w => w.Cells.Any(c => c.IsPointInside(p.Position.ToVector2())))); + } if (!suitablePositions.Any()) { string errorMsg = "Could not find a suitable position of interest. (PositionType: " + positionType + ", minDistFromSubs: " + minDistFromSubs + ")\n" + Environment.StackTrace; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 2cb8f3192..ec3110b71 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -1433,7 +1433,7 @@ namespace Barotrauma Submarine sub = new Submarine(path); sub.Load(unloadPrevious); - + return sub; } @@ -1564,6 +1564,94 @@ namespace Barotrauma PreviewImage = null; #endif } + + private List outdoorNodes; + private List OutdoorNodes + { + get + { + if (outdoorNodes == null) + { + outdoorNodes = PathNode.GenerateNodes(WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path && wp.Submarine == this && wp.CurrentHull == null)); + } + return outdoorNodes; + } + } + private HashSet obstructedNodes = new HashSet(); + + /// + /// Permanently disables obstructed waypoints obstructed by the level. + /// + public void DisableObstructedWayPoints() + { + // Check collisions to level + foreach (var node in OutdoorNodes) + { + if (node == null || node.Waypoint == null) { continue; } + var wp = node.Waypoint; + if (wp.isObstructed) { continue; } + foreach (var connection in node.connections) + { + bool isObstructed = false; + var connectedWp = connection.Waypoint; + if (connectedWp.isObstructed) { continue; } + Vector2 start = ConvertUnits.ToSimUnits(wp.WorldPosition); + Vector2 end = ConvertUnits.ToSimUnits(connectedWp.WorldPosition); + var body = Submarine.PickBody(start, end, null, Physics.CollisionLevel, allowInsideFixture: false); + if (body != null) + { + connectedWp.isObstructed = true; + wp.isObstructed = true; + break; + } + } + } + } + + /// + /// Temporarily disables waypoints obstructed by the other sub. + /// + public void DisableObstructedWayPoints(Submarine otherSub) + { + if (otherSub == null) { return; } + if (otherSub == this) { return; } + // Check collisions to other subs. Currently only walls are taken into account. + foreach (var node in OutdoorNodes) + { + if (node == null || node.Waypoint == null) { continue; } + var wp = node.Waypoint; + if (wp.isObstructed) { continue; } + foreach (var connection in node.connections) + { + bool isObstructed = false; + var connectedWp = connection.Waypoint; + if (connectedWp.isObstructed) { continue; } + Vector2 start = ConvertUnits.ToSimUnits(wp.WorldPosition) - otherSub.SimPosition; + Vector2 end = ConvertUnits.ToSimUnits(connectedWp.WorldPosition) - otherSub.SimPosition; + var body = Submarine.PickBody(start, end, null, Physics.CollisionWall, allowInsideFixture: false); + if (body != null && body.UserData is Structure && !((Structure)body.UserData).IsPlatform) + { + connectedWp.isObstructed = true; + wp.isObstructed = true; + obstructedNodes.Add(node); + obstructedNodes.Add(connection); + break; + } + } + } + } + + /// + /// Only affects temporarily disabled waypoints. + /// + public void EnableObstructedWaypoints() + { + foreach (var node in obstructedNodes) + { + node.Waypoint.isObstructed = false; + } + obstructedNodes.Clear(); + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs index e2df8eafb..4e9cefbe3 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs @@ -32,6 +32,8 @@ namespace Barotrauma public Ladder Ladders; public Structure Stairs; + public bool isObstructed; + private ushort gapId; public Gap ConnectedGap { diff --git a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs index f701bdf9a..501119553 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs @@ -7,6 +7,8 @@ namespace Barotrauma.Networking { partial class Client : IDisposable { + public const int MaxNameLength = 20; + public string Name; public byte ID; @@ -205,6 +207,21 @@ namespace Barotrauma.Networking SetPermissions(permissions, permittedCommands); } + public static string SanitizeName(string name) + { + name = name.Trim(); + if (name.Length > MaxNameLength) + { + name = name.Substring(0, MaxNameLength); + } + string rName = ""; + for (int i = 0; i < name.Length; i++) + { + rName += name[i] < 32 ? '?' : name[i]; + } + return rName; + } + public void Dispose() { DisposeProjSpecific(); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetworkMember.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetworkMember.cs index e7e60021b..2730bacb3 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetworkMember.cs @@ -174,8 +174,8 @@ namespace Barotrauma.Networking get { return name; } set { - if (string.IsNullOrEmpty(value)) return; - name = value; + if (string.IsNullOrEmpty(value)) { return; } + name = value.Replace(":", "").Replace(";", ""); } } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs index 0a2c470e5..98f6af3a2 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs @@ -158,41 +158,11 @@ namespace Barotrauma.Networking shuttleTransportTimer -= deltaTime; -#if CLIENT - GameClient nClient = networkMember as GameClient; - if (shuttleTransportTimer + deltaTime > 15.0f && shuttleTransportTimer <= 15.0f && - nClient.Character != null && - nClient.Character.Submarine == respawnShuttle) - { - nClient.AddChatMessage("ServerMessage.ShuttleLeaving", ChatMessageType.Server); - } -#endif - -#if SERVER - var server = networkMember as GameServer; - if (server == null) return; - - //if there are no living chracters inside, transporting can be stopped immediately - if (!Character.CharacterList.Any(c => c.Submarine == respawnShuttle && !c.IsDead)) - { - shuttleTransportTimer = 0.0f; - } - - if (shuttleTransportTimer <= 0.0f) - { - GameServer.Log("The respawn shuttle is leaving.", ServerLog.MessageType.ServerMessage); - state = State.Returning; - - server.CreateEntityEvent(this); - - CountdownStarted = false; - maxTransportTime = server.ServerSettings.MaxTransportTime; - shuttleReturnTimer = maxTransportTime; - shuttleTransportTimer = maxTransportTime; - } -#endif + UpdateTransportingProjSpecific(deltaTime); } + partial void UpdateTransportingProjSpecific(float deltaTime); + private void UpdateReturning(float deltaTime) { //if (shuttleReturnTimer == maxTransportTime && @@ -216,56 +186,13 @@ namespace Barotrauma.Networking { shuttleSteering.SetDestinationLevelStart(); } - - -#if SERVER - var server = networkMember as GameServer; - if (server == null) return; - - foreach (Door door in shuttleDoors) - { - if (door.IsOpen) door.TrySetState(false, false, true); - } - - var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == respawnShuttle && g.ConnectedWall != null); - shuttleGaps.ForEach(g => Spawner.AddToRemoveQueue(g)); - - var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == respawnShuttle && i.GetComponent() != null); - dockingPorts.ForEach(d => d.GetComponent().Undock()); - - //shuttle has returned if the path has been traversed or the shuttle is close enough to the exit - - if (!CoroutineManager.IsCoroutineRunning("forcepos")) - { - if ((shuttleSteering?.SteeringPath != null && shuttleSteering.SteeringPath.Finished) - || (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight && - Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f)) - { - CoroutineManager.StopCoroutines("forcepos"); - CoroutineManager.StartCoroutine( - ForceShuttleToPos(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f), 100.0f), "forcepos"); - - } - } - - if (respawnShuttle.WorldPosition.Y > Level.Loaded.Size.Y || shuttleReturnTimer <= 0.0f) - { - CoroutineManager.StopCoroutines("forcepos"); - - ResetShuttle(); - - state = State.Waiting; - GameServer.Log("The respawn shuttle has left.", ServerLog.MessageType.Spawning); - server.CreateEntityEvent(this); - - respawnTimer = server.ServerSettings.RespawnInterval; - CountdownStarted = false; - } -#endif + UpdateReturningProjSpecific(); } } partial void DispatchShuttle(); + + partial void UpdateReturningProjSpecific(); private IEnumerable ForceShuttleToPos(Vector2 position, float speed) { @@ -314,6 +241,7 @@ namespace Barotrauma.Networking //restore other items to full condition and recharge batteries item.Condition = item.Prefab.Health; + item.GetComponent()?.ResetDeterioration(); var powerContainer = item.GetComponent(); if (powerContainer != null) { diff --git a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub index b1d3cf6e9..1ba592d2a 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub and b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub index 4286ee8ec..4d2f3ab29 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub and b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Remora.sub b/Barotrauma/BarotraumaShared/Submarines/Remora.sub index 6f29eb586..2d8aeb250 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Remora.sub and b/Barotrauma/BarotraumaShared/Submarines/Remora.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub b/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub index 49ade4d29..b6bec76a8 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub and b/Barotrauma/BarotraumaShared/Submarines/RemoraDrone.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub index 110792142..bdda8e25a 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub differ