diff --git a/.gitignore b/.gitignore index bf5f81970..2afaafc0a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,6 @@ bld/ [Rr]elease*/ *.o -# Barotrauma content folder -BarotraumaShared/Content/ - # Misc vs crap *.v12.suo *.suo diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs index 9876cbc2c..3dc2aed42 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs @@ -176,6 +176,8 @@ namespace Barotrauma healthBar = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas), barSize: 1.0f, color: Color.Green, style: horizontal ? "GUIProgressBar" : "GUIProgressBarVertical") { + Enabled = true, + HoverCursor = CursorState.Hand, IsHorizontal = horizontal }; healthBarShadow = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas), diff --git a/Barotrauma/BarotraumaClient/ClientSource/ChatManager.cs b/Barotrauma/BarotraumaClient/ClientSource/ChatManager.cs index 8034e9ee4..bd21ba601 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/ChatManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/ChatManager.cs @@ -26,17 +26,14 @@ namespace Barotrauma /// where I'm utilizing this private readonly List registers = new List(); - private readonly bool skipDuplicate; - // Selector index private int index; // Local changes we've made into previously stored messages private string[] localChanges; - public ChatManager(bool skipDuplicate, bool loop, short maxCount) + public ChatManager(bool loop, short maxCount) { - this.skipDuplicate = skipDuplicate; this.loop = loop; this.maxCount = maxCount; localChanges = new string[maxCount]; @@ -87,13 +84,10 @@ namespace Barotrauma public void Store(string message) { Clear(); - string strip = StripMessage(message); + var strip = StripMessage(message); if (string.IsNullOrWhiteSpace(strip)) { return; } - if (skipDuplicate && messageList.Any(p => message == p)) - { - return; - } + if (messageList.Count > 1 && messageList[1] == message) { return; } // insert to the second position as the first position is reserved for the original message if any messageList.Insert(1, message); @@ -104,7 +98,7 @@ namespace Barotrauma } // [It's also possible to lambdas too in short methods, if you like: string StripMessage(string text) => ChatMessage.GetChatMessageCommand(text, out string msg);] - string StripMessage(string text) + static string StripMessage(string text) { ChatMessage.GetChatMessageCommand(text, out string msg); return msg; @@ -129,40 +123,61 @@ namespace Barotrauma /// A message or null private string SelectMessage(Direction direction, string original) { - if (direction == Direction.Other) { return null; } - - // temporarily save our changes in case we fat-finger and want to go back - localChanges[index] = original; - - int dir = (int) direction; - - int nextIndex = (index + dir); - - if (loop && messageList.Count > 1) + var originalIndex = index; + while (true) { - nextIndex = LoopAround(nextIndex); - } - else - { - if (nextIndex > messageList.Count - 1) + if (direction == Direction.Other) { return null; } - } - - return nextIndex < 0 ? localChanges.FirstOrDefault() : EntryAt(index = nextIndex); - - string EntryAt(int i) - { - // if we've previously edited the entry then give us that, else give us the original message - return localChanges[i] ?? messageList[i]; - } - int LoopAround(int next) - { - if (next > (messageList.Count - 1)) { return 1; } - if (next < 1) { return messageList.Count - 1; } - return next; + // temporarily save our changes in case we fat-finger and want to go back + localChanges[index] = original; + + var dir = (int) direction; + + var nextIndex = (index + dir); + + if (loop && messageList.Count > 1) + { + nextIndex = LoopAround(nextIndex); + } + else + { + if (nextIndex > messageList.Count - 1) + { + return null; + } + } + + if (nextIndex >= 0 && EntryAt(nextIndex) == original && nextIndex != originalIndex && originalIndex != 0) + { + index = nextIndex; + continue; + } + + return nextIndex < 0 ? localChanges.FirstOrDefault() : EntryAt(index = nextIndex); + + string EntryAt(int i) + { + // if we've previously edited the entry then give us that, else give us the original message + return localChanges[i] ?? messageList[i]; + } + + int LoopAround(int next) + { + if (next > (messageList.Count - 1)) + { + return 1; + } + + if (next < 1) + { + return messageList.Count - 1; + } + + return next; + } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs index b45fedcb0..a62eb9fcc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs @@ -61,7 +61,7 @@ namespace Barotrauma public static GUITextBox TextBox => textBox; - private static readonly ChatManager chatManager = new ChatManager(true, true, 64); + private static readonly ChatManager chatManager = new ChatManager(true, 64); public static void Init() { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs index 67bd9cefe..42c2c4ab2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs @@ -1,17 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.Linq; using Barotrauma.CharacterEditor; using Barotrauma.Extensions; +using Barotrauma.Items.Components; using Barotrauma.Networking; using Barotrauma.Sounds; -using Barotrauma.Tutorials; using EventInput; using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; namespace Barotrauma { @@ -26,11 +28,23 @@ namespace Barotrauma PickItemFail, DropItem } + + public enum CursorState + { + Default, // Cursor + Hand, // Hand with a finger + Move, // arrows pointing to all directions + IBeam, // Text + Dragging,// Closed hand + Waiting, // Hourglass + WaitingBackground // Cursor + Hourglass + } public static class GUI { public static GUICanvas Canvas => GUICanvas.Instance; - + public static CursorState MouseCursor = CursorState.Default; + public static readonly SamplerState SamplerState = new SamplerState() { Filter = TextureFilter.Linear, @@ -82,8 +96,7 @@ namespace Barotrauma public static GUIStyle Style; private static Texture2D t; - - private static Sprite Cursor => Style.CursorSprite; + private static Sprite[] MouseCursorSprites => Style.CursorSprite; private static bool debugDrawSounds, debugDrawEvents; @@ -184,7 +197,7 @@ namespace Barotrauma public static void Init(GameWindow window, IEnumerable selectedContentPackages, GraphicsDevice graphicsDevice) { - GUI.GraphicsDevice = graphicsDevice; + GraphicsDevice = graphicsDevice; var files = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle); XElement selectedStyle = null; @@ -306,7 +319,7 @@ namespace Barotrauma if (GameMain.ShowFPS || GameMain.DebugDraw) { DrawString(spriteBatch, new Vector2(10, 10), - "FPS: " + (int)GameMain.PerformanceCounter.AverageFramesPerSecond, + "FPS: " + Math.Round(GameMain.PerformanceCounter.AverageFramesPerSecond), Color.White, Color.Black * 0.5f, 0, SmallFont); } @@ -339,7 +352,7 @@ namespace Barotrauma y += 15; } - if (FarseerPhysics.Settings.EnableDiagnostics) + if (Settings.EnableDiagnostics) { DrawString(spriteBatch, new Vector2(320, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, Color.Red, (float)GameMain.World.ContinuousPhysicsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont); DrawString(spriteBatch, new Vector2(320, y + 15), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, Color.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, SmallFont); @@ -415,10 +428,10 @@ namespace Barotrauma } else { - soundStr += System.IO.Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename); + soundStr += Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename); #if DEBUG - if (PlayerInput.GetKeyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.G)) + if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.G)) { if (PlayerInput.MousePosition.Y >= y && PlayerInput.MousePosition.Y <= y + 12) { @@ -507,10 +520,13 @@ namespace Barotrauma if (GameMain.WindowActive && !HideCursor) { spriteBatch.End(); - spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable); - Cursor.Draw(spriteBatch, PlayerInput.LatestMousePosition, 0, Scale / 2f); + spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable); + + var sprite = MouseCursorSprites[(int) MouseCursor]; + sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f); + spriteBatch.End(); - spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); + spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable); } HideCursor = false; } @@ -723,13 +739,14 @@ namespace Barotrauma GUIComponent prevMouseOn = MouseOn; MouseOn = null; int inventoryIndex = -1; + if (Inventory.IsMouseOnInventory()) { inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame); } - for (int i = updateList.Count - 1; i > inventoryIndex; i--) + for (var i = updateList.Count - 1; i > inventoryIndex; i--) { - GUIComponent c = updateList[i]; + var c = updateList[i]; if (!c.CanBeFocused) { continue; } if (c.MouseRect.Contains(PlayerInput.MousePosition)) { @@ -740,8 +757,198 @@ namespace Barotrauma break; } } + + MouseCursor = UpdateMouseCursorState(MouseOn); return MouseOn; } + + private static CursorState UpdateMouseCursorState(GUIComponent c) + { + // Waiting and drag cursor override everything else + if (MouseCursor == CursorState.Waiting) { return CursorState.Waiting; } + if (GUIScrollBar.DraggingBar != null) { return GUIScrollBar.DraggingBar.Bar.HoverCursor; } + + // Wire cursors + if (ConnectionPanel.HighlightedWire != null) { return CursorState.Hand; } + if (Wire.DraggingWire != null) { return CursorState.Dragging; } + if (Connection.DraggingConnected != null) { return CursorState.Dragging; } + + if (c == null || c is GUICustomComponent) + { + switch (Screen.Selected) + { + // Character editor limbs + case CharacterEditorScreen editor: + return editor.GetMouseCursorState(); + // Portrait area during gameplay + case GameScreen _ when HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition): + return CursorState.Hand; + // Sub editor drag and highlight + case SubEditorScreen editor: + { + // Portrait area + if ((editor.CharacterMode || editor.WiringMode) && + HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition)) + { + return CursorState.Hand; + } + + foreach (var mapEntity in MapEntity.mapEntityList) + { + if (MapEntity.StartMovingPos != Vector2.Zero) + { + return CursorState.Dragging; + } + if (mapEntity.IsHighlighted) + { + return CursorState.Hand; + } + } + break; + } + + // Campaign map highlighted location + case LobbyScreen lobby: + { + if (lobby.CampaignUI?.Campaign.Map.HighlightedLocation != null) { return CursorState.Hand; } + break; + } + + case NetLobbyScreen lobby: + { + if (lobby.CampaignUI?.Campaign.Map.HighlightedLocation != null) { return CursorState.Hand; } + break; + } + } + } + + if (c != null && c.Visible) + { + // When a button opens a submenu, it increases to the size of the entire screen. + // And this is of course picked up as clickable area. + // There has to be a better way of checking this but for now this works. + var monitorRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight); + + var parent = FindInteractParent(c); + + if (c.Enabled) + { + // Some parent elements take priority + // but not when the child is a GUIButton or GUITickBox + if (!(parent is GUIButton) && !(parent is GUIListBox) || + (c is GUIButton) || (c is GUITickBox)) + { + if (!c.Rect.Equals(monitorRect)) { return c.HoverCursor; } + } + } + + // Children in list boxes can be interacted with despite not having + // a GUIButton inside of them so instead of hard coding we check if + // the children can be interacted with by checking their hover state + if (parent is GUIListBox) + { + var hoverParent = c; + while (true) + { + if (hoverParent == parent || hoverParent == null) { break; } + if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; } + hoverParent = hoverParent.Parent; + } + } + + if (parent != null) + { + if (!parent.Rect.Equals(monitorRect)) { return parent.HoverCursor; } + } + } + + if (Inventory.IsMouseOnInventory()) { return Inventory.GetInventoryMouseCursor(); } + + var character = Character.Controlled; + // ReSharper disable once InvertIf + if (character != null) + { + // Health menus + if (character.CharacterHealth.MouseOnElement) { return CursorState.Hand; } + + if (character.SelectedCharacter != null) + { + if (character.SelectedCharacter.CharacterHealth.MouseOnElement) + { + return CursorState.Hand; + } + } + + // Character is hovering over an item placed in the world + if (character.FocusedItem != null) { return CursorState.Hand; } + } + + return CursorState.Default; + + static GUIComponent FindInteractParent(GUIComponent component) + { + while (true) + { + var parent = component.Parent; + if (parent == null) { return null; } + + if (ContainsMouse(parent)) + { + if (parent.Enabled) + { + switch (parent) + { + case GUIButton button: + return button; + case GUITextBox box: + return box; + case GUIListBox list: + return list; + case GUIScrollBar bar: + return bar; + } + } + component = parent; + } + else + { + return null; + } + } + } + + static bool ContainsMouse(GUIComponent component) + { + // If component has a mouse rectangle then use that, if not use it's physical rect + return !component.MouseRect.Equals(Rectangle.Empty) ? + component.MouseRect.Contains(PlayerInput.MousePosition) : + component.Rect.Contains(PlayerInput.MousePosition); + } + } + + /// + /// Set the cursor to an hourglass. + /// Will automatically revert after 10 seconds or when is called. + /// + public static void SetCursorWaiting() + { + CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout"); + + static IEnumerable WaitCursorCoroutine() + { + MouseCursor = CursorState.Waiting; + var timeOut = DateTime.Now + new TimeSpan(0, 0, 10); + while (DateTime.Now < timeOut) { yield return CoroutineStatus.Running; } + if (MouseCursor == CursorState.Waiting) { MouseCursor = CursorState.Default; } + yield return CoroutineStatus.Success; + } + } + + public static void ClearCursorWait() + { + CoroutineManager.StopCoroutines("WaitCursorTimeout"); + MouseCursor = CursorState.Default; + } public static bool HasSizeChanged(Point referenceResolution, float referenceUIScale, float referenceHUDScale) { @@ -754,7 +961,7 @@ namespace Barotrauma HandlePersistingElements(deltaTime); RefreshUpdateList(); UpdateMouseOn(); - System.Diagnostics.Debug.Assert(updateList.Count == updateListSet.Count); + Debug.Assert(updateList.Count == updateListSet.Count); updateList.ForEach(c => c.UpdateAuto(deltaTime)); UpdateMessages(deltaTime); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs index 800e685d9..354caa070 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIButton.cs @@ -154,6 +154,7 @@ namespace Barotrauma public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null, ScalableFont font = null) : base(style, rectT) { CanBeFocused = true; + HoverCursor = CursorState.Hand; if (color.HasValue) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs index 57a269fa8..fc1c67567 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIComponent.cs @@ -16,6 +16,8 @@ namespace Barotrauma #region Hierarchy public GUIComponent Parent => RectTransform.Parent?.GUIComponent; + public CursorState HoverCursor = CursorState.Default; + public IEnumerable Children => RectTransform.Children.Select(c => c.GUIComponent); public T GetChild() where T : GUIComponent diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs index f6d564c72..0166e3510 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIDropDown.cs @@ -147,6 +147,7 @@ namespace Barotrauma public GUIDropDown(RectTransform rectT, string text = "", int elementCount = 4, string style = "", bool selectMultiple = false, bool dropAbove = false) : base(style, rectT) { + HoverCursor = CursorState.Hand; CanBeFocused = true; this.selectMultiple = selectMultiple; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIScrollBar.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIScrollBar.cs index 027dc483e..1e3d75944 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIScrollBar.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIScrollBar.cs @@ -192,12 +192,28 @@ namespace Barotrauma public GUIScrollBar(RectTransform rectT, float barSize = 1, Color? color = null, string style = "", bool? isHorizontal = null) : base(style, rectT) { CanBeFocused = true; - this.isHorizontal = isHorizontal ?? (Rect.Width > Rect.Height); Frame = new GUIFrame(new RectTransform(Vector2.One, rectT)); GUI.Style.Apply(Frame, IsHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this); this.barSize = barSize; Bar = new GUIButton(new RectTransform(Vector2.One, rectT, IsHorizontal ? Anchor.CenterLeft : Anchor.TopCenter), color: color); + + switch (style) + { + case "": + HoverCursor = CursorState.Default; + Bar.HoverCursor = CursorState.Default; + break; + case "GUISlider": + HoverCursor = CursorState.Default; + Bar.HoverCursor = CursorState.Hand; + break; + default: + HoverCursor = CursorState.Hand; + Bar.HoverCursor = CursorState.Hand; + break; + } + GUI.Style.Apply(Bar, IsHorizontal ? "GUIButtonHorizontal" : "GUIButtonVertical", this); Bar.OnPressed = SelectBar; enabled = true; @@ -222,8 +238,6 @@ namespace Barotrauma { if (!Visible) { return; } - base.Update(deltaTime); - if (!enabled) { return; } Frame.State = GUI.MouseOn == Frame ? ComponentState.Hover : ComponentState.None; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs index b54440163..8acb44547 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIStyle.cs @@ -25,7 +25,7 @@ namespace Barotrauma public ScalableFont ObjectiveTitleFont { get; private set; } public ScalableFont ObjectiveNameFont { get; private set; } - public Sprite CursorSprite { get; private set; } + public readonly Sprite[] CursorSprite = new Sprite[7]; public UISprite UIGlow { get; private set; } @@ -38,10 +38,15 @@ namespace Barotrauma configElement = element; foreach (XElement subElement in configElement.Elements()) { - switch (subElement.Name.ToString().ToLowerInvariant()) + var name = subElement.Name.ToString().ToLowerInvariant(); + switch (name) { case "cursor": - CursorSprite = new Sprite(subElement); + foreach (var children in subElement.Descendants()) + { + var index = children.GetAttributeInt("state", (int) CursorState.Default); + CursorSprite[index] = new Sprite(children); + } break; case "uiglow": UIGlow = new UISprite(subElement); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBox.cs index 592d6b8d5..5c90c1f8f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITextBox.cs @@ -231,6 +231,7 @@ namespace Barotrauma Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null) : base(style, rectT) { + HoverCursor = CursorState.IBeam; CanBeFocused = true; Enabled = true; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITickBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITickBox.cs index 3deea2c97..60a43228e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITickBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUITickBox.cs @@ -134,6 +134,7 @@ namespace Barotrauma public GUITickBox(RectTransform rectT, string label, ScalableFont font = null, string style = "") : base(null, rectT) { CanBeFocused = true; + HoverCursor = CursorState.Hand; layoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), true); @@ -176,6 +177,7 @@ namespace Barotrauma protected override void Update(float deltaTime) { if (!Visible) return; + base.Update(deltaTime); if (GUI.MouseOn == this && Enabled) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs index c3343cea0..5fd3c40eb 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs @@ -891,7 +891,13 @@ namespace Barotrauma double deltaTime = gameTime.ElapsedGameTime.TotalSeconds; - PerformanceCounter.Update(deltaTime); + double step = 1.0 / Timing.FrameLimit; + while (!Config.VSyncEnabled && sw.Elapsed.TotalSeconds + deltaTime < step) + { + Thread.Sleep(1); + } + + PerformanceCounter.Update(sw.Elapsed.TotalSeconds + deltaTime); if (loadingScreenOpen) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs index e48462988..6eb6a291f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs @@ -97,7 +97,10 @@ namespace Barotrauma.Tutorials stunbaton.Unequip(officer); officer.Inventory.RemoveItem(stunbaton); - var ballistichelmet = FindOrGiveItem(officer, "ballistichelmet"); + var ballistichelmet = + officer.Inventory.FindItemByIdentifier("ballistichelmet1") ?? + officer.Inventory.FindItemByIdentifier("ballistichelmet2") ?? + FindOrGiveItem(officer, "ballistichelmet3"); ballistichelmet.Unequip(officer); officer.Inventory.RemoveItem(ballistichelmet); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs index a405a4d05..946db2f4a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs @@ -24,6 +24,12 @@ namespace Barotrauma.Items.Components { get { return flashTimer; } } + + public static Wire DraggingConnected + { + get => draggingConnected; + } + private float flashTimer; public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Wire.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Wire.cs index 9f2442588..7de5cda92 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Wire.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Wire.cs @@ -51,6 +51,11 @@ namespace Barotrauma.Items.Components get { return sectionExtents; } } + public static Wire DraggingWire + { + get => draggingWire; + } + partial void InitProjSpecific(XElement element) { if (defaultWireSprite == null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index 560de9e8e..c8ea831a4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -653,10 +653,19 @@ namespace Barotrauma if (Character.Controlled.Inventory != null) { - foreach (InventorySlot slot in Character.Controlled.Inventory.slots) + var inv = Character.Controlled.Inventory; + for (var i = 0; i < inv.slots.Length; i++) { - if (slot.InteractRect.Contains(PlayerInput.MousePosition) || - slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) + var slot = inv.slots[i]; + if (slot.InteractRect.Contains(PlayerInput.MousePosition)) + { + return true; + } + + // check if the equip button actually exists + if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && + i >= 0 && inv.Items.Length > i && + inv.Items[i] != null) { return true; } @@ -664,10 +673,19 @@ namespace Barotrauma } if (Character.Controlled.SelectedCharacter?.Inventory != null) { - foreach (InventorySlot slot in Character.Controlled.SelectedCharacter.Inventory.slots) + var inv = Character.Controlled.SelectedCharacter.Inventory; + for (var i = 0; i < inv.slots.Length; i++) { - if (slot.InteractRect.Contains(PlayerInput.MousePosition) || - slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) + var slot = inv.slots[i]; + if (slot.InteractRect.Contains(PlayerInput.MousePosition)) + { + return true; + } + + // check if the equip button actually exists + if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition) && + i >= 0 && inv.Items.Length > i && + inv.Items[i] != null) { return true; } @@ -676,7 +694,7 @@ namespace Barotrauma if (Character.Controlled.SelectedConstruction != null) { - foreach (ItemComponent ic in Character.Controlled.SelectedConstruction.Components) + foreach (var ic in Character.Controlled.SelectedConstruction.ActiveHUDs) { var itemContainer = ic as ItemContainer; if (itemContainer?.Inventory?.slots == null) continue; @@ -699,6 +717,88 @@ namespace Barotrauma return false; } + + public static CursorState GetInventoryMouseCursor() + { + var character = Character.Controlled; + if (character == null) { return CursorState.Default; } + if (draggingItem != null || DraggingInventory != null) { return CursorState.Dragging; } + + var inv = character.Inventory; + var selInv = character.SelectedCharacter?.Inventory; + + if (inv == null) { return CursorState.Default; } + + foreach (var item in inv.Items) + { + var container = item?.GetComponent(); + if (container == null) { continue; } + + if (container.Inventory.slots != null) + { + if (container.Inventory.slots.Any(slot => slot.IsHighlighted)) + { + return CursorState.Hand; + } + } + + if (container.Inventory.movableFrameRect.Contains(PlayerInput.MousePosition)) + { + return CursorState.Move; + } + } + + + if (selInv != null) + { + foreach (var slot in selInv.slots) + { + if (slot.InteractRect.Contains(PlayerInput.MousePosition) || + slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) + { + return CursorState.Hand; + } + } + } + + if (character.SelectedConstruction != null) + { + foreach (var ic in character.SelectedConstruction.ActiveHUDs) + { + var itemContainer = ic as ItemContainer; + if (itemContainer?.Inventory?.slots == null) continue; + + foreach (var slot in itemContainer.Inventory.slots) + { + if (slot.InteractRect.Contains(PlayerInput.MousePosition) || + slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) + { + return CursorState.Hand; + } + } + } + } + + foreach (var slot in inv.slots) + { + if (slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) + { + return CursorState.Hand; + } + + // This is the only place we double check this because if we have a inventory container + // highlighting any area within that container registers as highlighting the + // original slot the item is in thus giving us a false hand cursor. + if (slot.InteractRect.Contains(PlayerInput.MousePosition)) + { + if (slot.IsHighlighted) + { + return CursorState.Hand; + } + } + } + return CursorState.Default; + } protected static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle highlightedSlot, List colorData = null) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs index 55b51ff0a..cb07ca96b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs @@ -88,8 +88,15 @@ namespace Barotrauma float arrowWidth = 32.0f; float arrowSize = 15.0f; + bool invalidDir = false; + if (dir == Vector2.Zero) + { + invalidDir = true; + dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY; + } + GUI.Arrow.Draw(sb, - arrowPos, clr * 0.8f, + arrowPos, invalidDir ? Color.Red : clr * 0.8f, GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2, IsHorizontal ? new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) : diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs index 1c8b4ef63..1188ea50b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs @@ -44,6 +44,8 @@ namespace Barotrauma private Location highlightedLocation; + public Location HighlightedLocation => highlightedLocation; + private Vector2 drawOffset; private Vector2 drawOffsetNoise; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs index 9dcdf50b8..796482cc1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/MapEntity.cs @@ -13,7 +13,9 @@ namespace Barotrauma protected static Vector2 selectionPos = Vector2.Zero; protected static Vector2 selectionSize = Vector2.Zero; - protected static Vector2 startMovingPos = Vector2.Zero; + private static Vector2 startMovingPos = Vector2.Zero; + + public static Vector2 StartMovingPos => startMovingPos; private static bool resizing; private int resizeDirX, resizeDirY; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs index b441ffc38..c0b8257c6 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ChatMessage.cs @@ -66,7 +66,7 @@ namespace Barotrauma.Networking } txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption); - if (GameMain.Client.GameStarted) + if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen) { if (order.TargetAllCharacters) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index a01ff2f96..eaf08af43 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -401,6 +401,7 @@ namespace Barotrauma.Networking // Before main looping starts, we loop here and wait for approval message private IEnumerable WaitForStartingInfo() { + GUI.SetCursorWaiting(); requiresPw = false; pwRetries = -1; @@ -503,6 +504,7 @@ namespace Barotrauma.Networking reconnectBox?.Close(); reconnectBox = null; + GUI.ClearCursorWait(); if (connectCancelled) { yield return CoroutineStatus.Success; } yield return CoroutineStatus.Success; @@ -1435,6 +1437,11 @@ namespace Barotrauma.Networking if (clientPeer is SteamP2POwnerPeer) { + TaskPool.Add(Steamworks.SteamNetworkingUtils.WaitForPingDataAsync(), (task) => + { + Steam.SteamManager.UpdateLobby(serverSettings); + }); + Steam.SteamManager.UpdateLobby(serverSettings); } } @@ -1978,7 +1985,7 @@ namespace Barotrauma.Networking if (ChildServerRelay.Process != null) { int checks = 0; - while (!ChildServerRelay.Process.HasExited) + while (ChildServerRelay.Process != null && !ChildServerRelay.Process.HasExited) { if (checks > 10) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerInfo.cs index ad02f1747..3a73813b3 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerInfo.cs @@ -509,11 +509,6 @@ namespace Barotrauma.Networking IP = ""; Port = ""; QueryPort = ""; - string pingLocation = lobby.GetData("pinglocation"); - if (!string.IsNullOrEmpty(pingLocation)) - { - PingLocation = Steamworks.Data.PingLocation.TryParseFromString(pingLocation); - } PlayerCount = currPlayers; MaxPlayers = maxPlayers; HasPassword = hasPassword; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/SteamManager.cs index 7a94431c4..94866241f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/SteamManager.cs @@ -118,6 +118,8 @@ namespace Barotrauma.Steam TaskPool.Add(Steamworks.SteamMatchmaking.CreateLobbyAsync(serverSettings.MaxPlayers + 10), (lobby) => { + currentLobby = lobby.Result; + if (currentLobby == null) { DebugConsole.ThrowError("Failed to create Steam lobby"); @@ -125,8 +127,6 @@ namespace Barotrauma.Steam return; } - currentLobby = lobby.Result; - DebugConsole.NewMessage("Lobby created!", Microsoft.Xna.Framework.Color.Lime); lobbyState = LobbyState.Owner; @@ -169,7 +169,8 @@ namespace Barotrauma.Steam currentLobby?.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count ?? 0).ToString()); currentLobby?.SetData("maxplayernum", serverSettings.MaxPlayers.ToString()); //currentLobby?.SetData("hostipaddress", lobbyIP); - currentLobby?.SetData("pinglocation", Steamworks.SteamNetworkingUtils.LocalPingLocation.ToString() ?? ""); + string pingLocation = Steamworks.SteamNetworkingUtils.LocalPingLocation.ToString(); + currentLobby?.SetData("pinglocation", pingLocation ?? ""); currentLobby?.SetData("lobbyowner", SteamIDUInt64ToString(GetSteamID())); currentLobby?.SetData("haspassword", serverSettings.HasPassword.ToString()); @@ -254,6 +255,7 @@ namespace Barotrauma.Steam ServerInfo serverInfo = new ServerInfo(); serverInfo.ServerName = lobby.GetData("name"); + serverInfo.OwnerID = SteamIDStringToUInt64(lobby.GetData("lobbyowner")); serverInfo.LobbyID = lobby.Id; serverInfo.PlayerCount = int.TryParse(lobby.GetData("playercount"), out int playerCount) ? playerCount : 0; serverInfo.MaxPlayers = int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers) ? maxPlayers : 1; @@ -371,6 +373,12 @@ namespace Barotrauma.Steam serverInfo.ContentPackageHashes.Clear(); } + string pingLocation = lobby.GetData("pinglocation"); + if (!string.IsNullOrEmpty(pingLocation)) + { + serverInfo.PingLocation = Steamworks.Data.PingLocation.TryParseFromString(pingLocation); + } + bool? getLobbyBool(string key) { string data = lobby.GetData(key); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Program.cs b/Barotrauma/BarotraumaClient/ClientSource/Program.cs index 465289bb2..d0d1b41c5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Program.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Program.cs @@ -112,6 +112,7 @@ namespace Barotrauma if (GameMain.Config != null) { sb.AppendLine("Graphics mode: " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight + " (" + GameMain.Config.WindowMode.ToString() + ")"); + sb.AppendLine("VSync "+ (GameMain.Config.VSyncEnabled ? "ON" : "OFF")); } if (GameMain.SelectedPackages != null) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs index 32dc33e84..0cebb23c6 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI.cs @@ -244,6 +244,7 @@ namespace Barotrauma private IEnumerable WaitForCampaignSetup() { + GUI.SetCursorWaiting(); string headerText = TextManager.Get("CampaignStartingPleaseWait"); var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new string[] { TextManager.Get("Cancel") }); @@ -251,6 +252,7 @@ namespace Barotrauma { GameMain.NetLobbyScreen.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex); GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex); + GUI.ClearCursorWait(); CoroutineManager.StopCoroutines("WaitForCampaignSetup"); return true; }; @@ -263,6 +265,7 @@ namespace Barotrauma yield return CoroutineStatus.Running; } msgBox.Close(); + GUI.ClearCursorWait(); yield return CoroutineStatus.Success; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index 1c5a06bb0..316ba7657 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -746,6 +746,21 @@ namespace Barotrauma.CharacterEditor buttonsPanelToggle?.UpdateOpenState((float)deltaTime, new Vector2(-buttonsPanel.Rect.Width - leftArea.RectTransform.AbsoluteOffset.X, 0), buttonsPanel.RectTransform); } + public CursorState GetMouseCursorState() + { + foreach (var limb in character.AnimController.Limbs) + { + if (limb?.ActiveSprite == null) { continue; } + if (selectedJoints.Any(j => j.LimbA == limb || j.LimbB == limb)) { continue; } + // character limbs + if (editLimbs && !spriteSheetRect.Contains(PlayerInput.MousePosition) && + MathUtils.RectangleContainsPoint(GetLimbPhysicRect(limb), PlayerInput.MousePosition)) { return CursorState.Hand; } + // spritesheet + if (GetLimbSpritesheetRect(limb).Contains(PlayerInput.MousePosition)) { return CursorState.Hand; } + } + return CursorState.Default; + } + /// /// Fps independent mouse input. The draw method is called multiple times per frame. /// diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LobbyScreen.cs index 06c36a881..7a3818d74 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LobbyScreen.cs @@ -18,6 +18,11 @@ namespace Barotrauma get { return GameMain.GameSession.CrewManager; } } + public CampaignUI CampaignUI + { + get { return campaignUI; } + } + public string GetMoney() { return campaignUI == null ? "" : campaignUI.GetMoney(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs index 8f08d7a4e..c8b822797 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs @@ -545,10 +545,10 @@ namespace Barotrauma break; case Tab.CharacterEditor: Submarine.MainSub = null; - GameMain.CharacterEditorScreen.Select(); + CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.CharacterEditorScreen)); break; case Tab.SubmarineEditor: - GameMain.SubEditorScreen.Select(); + CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.SubEditorScreen)); break; case Tab.QuickStartDev: QuickStart(); @@ -560,7 +560,7 @@ namespace Barotrauma break; case Tab.SteamWorkshop: if (!Steam.SteamManager.IsInitialized) return false; - GameMain.SteamWorkshopScreen.Select(); + CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.SteamWorkshopScreen)); break; case Tab.Credits: titleText.Visible = false; @@ -577,6 +577,16 @@ namespace Barotrauma return true; } + private IEnumerable SelectScreenWithWaitCursor(Screen screen) + { + GUI.SetCursorWaiting(); + //tiny delay to get the cursor to render + yield return new WaitForSeconds(0.02f); + GUI.ClearCursorWait(); + screen.Select(); + yield return CoroutineStatus.Success; + } + public bool ReturnToMainMenu(GUIButton button, object obj) { GUI.PreventPauseMenuToggle = false; @@ -1165,7 +1175,8 @@ namespace Barotrauma maxPlayersBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform), textAlignment: Alignment.Center) { Text = maxPlayers.ToString(), - Enabled = false + // ? + // Enabled = false }; new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform), "+", textAlignment: Alignment.Center) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index c1eb23051..01ea45052 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -1080,6 +1080,7 @@ namespace Barotrauma public IEnumerable WaitForStartRound(GUIButton startButton, bool allowCancel) { + GUI.SetCursorWaiting(); string headerText = TextManager.Get("RoundStartingPleaseWait"); var msgBox = new GUIMessageBox(headerText, TextManager.Get("RoundStarting"), allowCancel ? new string[] { TextManager.Get("Cancel") } : new string[0]); @@ -1091,6 +1092,7 @@ namespace Barotrauma startButton.Enabled = true; GameMain.Client.RequestRoundEnd(); CoroutineManager.StopCoroutines("WaitForStartRound"); + GUI.ClearCursorWait(); return true; }; msgBox.Buttons[0].OnClicked += msgBox.Close; @@ -1113,7 +1115,7 @@ namespace Barotrauma { startButton.Enabled = true; } - + GUI.ClearCursorWait(); yield return CoroutineStatus.Success; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs index b2c1099f0..72296fff0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen.cs @@ -147,6 +147,8 @@ namespace Barotrauma private DateTime refreshDisableTimer; private bool waitingForRefresh; + private bool steamPingInfoReady; + private const float sidebarWidth = 0.2f; public ServerListScreen() { @@ -1423,6 +1425,15 @@ namespace Barotrauma { if (waitingForRefresh) { return; } + steamPingInfoReady = false; + + CoroutineManager.StopCoroutines("EstimateLobbyPing"); + + TaskPool.Add(Steamworks.SteamNetworkingUtils.WaitForPingDataAsync(), (task) => + { + steamPingInfoReady = true; + }); + friendsListUpdateTime = Timing.TotalTime - 1.0; UpdateFriendsList(); @@ -1684,11 +1695,7 @@ namespace Barotrauma } else if (serverInfo.PingLocation != null) { - Steamworks.Data.PingLocation pingLocation = serverInfo.PingLocation.Value; - serverInfo.Ping = Steamworks.SteamNetworkingUtils.LocalPingLocation?.EstimatePingTo(pingLocation) ?? -1; - serverInfo.PingChecked = true; - serverPingText.TextColor = GetPingTextColor(serverInfo.Ping); - serverPingText.Text = serverInfo.Ping > -1 ? serverInfo.Ping.ToString() : "?"; + CoroutineManager.StartCoroutine(EstimateLobbyPing(serverInfo, serverPingText), "EstimateLobbyPing"); } if (serverInfo.LobbyID == 0 && (string.IsNullOrWhiteSpace(serverInfo.IP) || string.IsNullOrWhiteSpace(serverInfo.Port))) @@ -1749,6 +1756,22 @@ namespace Barotrauma FilterServers(); } + private IEnumerable EstimateLobbyPing(ServerInfo serverInfo, GUITextBlock serverPingText) + { + while (!steamPingInfoReady) + { + yield return CoroutineStatus.Running; + } + + Steamworks.Data.PingLocation pingLocation = serverInfo.PingLocation.Value; + serverInfo.Ping = Steamworks.SteamNetworkingUtils.LocalPingLocation?.EstimatePingTo(pingLocation) ?? -1; + serverInfo.PingChecked = true; + serverPingText.TextColor = GetPingTextColor(serverInfo.Ping); + serverPingText.Text = serverInfo.Ping > -1 ? serverInfo.Ping.ToString() : "?"; + + yield return CoroutineStatus.Success; + } + private void ServerQueryFinished() { if (!serverList.Content.Children.Any()) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index 0e48099a6..0dc69bdea 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -1435,7 +1435,7 @@ namespace Barotrauma #if DEBUG deleteBtn.Enabled = true; #else - deleteBtn.Enabled = userData is Submarine sub && sub.IsVanillaSubmarine(); + deleteBtn.Enabled = userData is Submarine sub && !sub.IsVanillaSubmarine(); #endif } return true; diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 1b41990d6..1509d2d51 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index e996a62a4..e7ff4f8da 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 5169849cc..aed256881 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index e63ef050e..dc3176212 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index a44b2b5fd..27ccac0b4 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/NetEntityEvent/ServerEntityEventManager.cs index b51b0704e..e687b9e70 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -313,11 +313,11 @@ namespace Barotrauma.Networking List eventsToSync = null; if (client.NeedsMidRoundSync) { - eventsToSync = GetEventsToSync(client, uniqueEvents); + eventsToSync = GetEventsToSync(client); } else { - eventsToSync = GetEventsToSync(client, events); + eventsToSync = GetEventsToSync(client); } if (eventsToSync.Count == 0) @@ -380,13 +380,13 @@ namespace Barotrauma.Networking /// /// Returns a list of events that should be sent to the client from the eventList /// - /// - /// - /// - private List GetEventsToSync(Client client, List eventList) + private List GetEventsToSync(Client client) { List eventsToSync = new List(); - if (eventList.Count == 0) return eventsToSync; + + var eventList = client.NeedsMidRoundSync ? uniqueEvents : events; + + if (eventList.Count == 0) { return eventsToSync; } //find the index of the first event the client hasn't received int startIndex = eventList.Count; @@ -409,7 +409,18 @@ namespace Barotrauma.Networking continue; } - eventsToSync.AddRange(eventList.GetRange(i, eventList.Count - i)); + if (client.NeedsMidRoundSync) + { + if (i <= client.UnreceivedEntityEventCount) + { + eventsToSync.AddRange(eventList.GetRange(i, client.UnreceivedEntityEventCount - i)); + } + } + else + { + eventsToSync.AddRange(eventList.GetRange(i, eventList.Count - i)); + } + break; } diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 78ef122eb..8f179e660 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.9.700.0 + 0.9.701.0 Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index f69c30060..c47d98feb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -980,8 +980,7 @@ namespace Barotrauma public void GiveJobItems(WayPoint spawnPoint = null) { - if (info == null || info.Job == null) return; - + if (info == null || info.Job == null) { return; } info.Job.GiveJobItems(this, spawnPoint); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs index 2699c3473..9b7aee2c2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentPackage.cs @@ -420,7 +420,7 @@ namespace Barotrauma if (logging) { var fileMd5 = new Md5Hash(hash); - DebugConsole.NewMessage(" " + file.Path + ": " + fileMd5.ShortHash); + DebugConsole.NewMessage(" " + file.Path + ": " + fileMd5.Hash); } hashes.Add(hash); } @@ -440,7 +440,7 @@ namespace Barotrauma md5Hash = new Md5Hash(bytes); if (logging) { - DebugConsole.NewMessage("****************************** Package hash: " + md5Hash.ShortHash); + DebugConsole.NewMessage("****************************** Package hash: " + md5Hash.Hash); } } @@ -470,6 +470,14 @@ namespace Barotrauma break; } + if (filePaths.Count > 1) + { + using (MD5 tempMd5 = MD5.Create()) + { + filePaths = filePaths.OrderBy(f => ToolBox.StringToUInt32Hash(f.CleanUpPathCrossPlatform(true), tempMd5)).ToList(); + } + } + foreach (string filePath in filePaths) { if (!File.Exists(filePath)) continue; diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 3cb4cfa99..3da49b115 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -489,6 +489,14 @@ namespace Barotrauma } })); + commands.Add(new Command("dumptofile", "", (string[] args) => + { + string filename = "consoleOutput.txt"; + if (args.Length > 0) { filename = string.Join(" ", args); } + + File.WriteAllLines(filename, Messages.Select(m => m.Text).ToArray()); + })); + commands.Add(new Command("findentityids", "findentityids [entityname]", (string[] args) => { if (args.Length == 0) return; @@ -924,6 +932,12 @@ namespace Barotrauma })); commands.Add(new Command("difficulty|leveldifficulty", "difficulty [0-100]: Change the level difficulty setting in the server lobby.", null)); + + commands.Add(new Command("autoitemplacerdebug|outfitdebug", "autoitemplacerdebug: Toggle automatic item placer debug info on/off. The automatically placed items are listed in the debug console at the start of a round.", (string[] args) => + { + AutoItemPlacer.OutputDebugInfo = !AutoItemPlacer.OutputDebugInfo; + NewMessage((AutoItemPlacer.OutputDebugInfo ? "Enabled" : "Disabled") + " automatic item placer logging.", Color.White); + }, isCheat: false)); commands.Add(new Command("verboselogging", "verboselogging: Toggle verbose console logging on/off. When on, additional debug information is written to the debug console.", (string[] args) => { @@ -1373,10 +1387,7 @@ namespace Barotrauma var variant = job != null ? Rand.Range(0, job.Variants, Rand.RandSync.Server) : 0; CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, variant: variant); spawnedCharacter = Character.Create(characterInfo, spawnPosition, ToolBox.RandomSeed(8)); - if (job != null) - { - spawnedCharacter.GiveJobItems(spawnPoint); - } + spawnedCharacter.GiveJobItems(spawnPoint); if (GameMain.GameSession != null) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/AutoItemPlacer.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/AutoItemPlacer.cs index fd114b2d4..1a1393d35 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/AutoItemPlacer.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/AutoItemPlacer.cs @@ -10,6 +10,8 @@ namespace Barotrauma { private static readonly List spawnedItems = new List(); + public static bool OutputDebugInfo = false; + public static void PlaceIfNeeded(GameMode gameMode) { if (GameMain.NetworkMember != null && !GameMain.NetworkMember.IsServer) { return; } @@ -82,14 +84,24 @@ namespace Barotrauma // Spawn items that don't have containers last prefabsWithoutContainer.Randomize().ForEach(i => SpawnItems(i)); - DebugConsole.NewMessage("Automatically placed items: "); - foreach (string itemName in spawnedItems.Select(it => it.Name).Distinct()) + if (OutputDebugInfo) { - DebugConsole.NewMessage(" - " + itemName + " x" + spawnedItems.Count(it => it.Name == itemName)); + DebugConsole.NewMessage("Automatically placed items: "); + foreach (string itemName in spawnedItems.Select(it => it.Name).Distinct()) + { + DebugConsole.NewMessage(" - " + itemName + " x" + spawnedItems.Count(it => it.Name == itemName)); + } } bool SpawnItems(ItemPrefab itemPrefab) { + if (itemPrefab == null) + { + string errorMsg = "Error in AutoItemPlacer.SpawnItems - itemPrefab was null.\n"+Environment.StackTrace; + DebugConsole.ThrowError(errorMsg); + GameAnalyticsManager.AddErrorEventOnce("AutoItemPlacer.SpawnItems:ItemNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); + return false; + } bool success = false; foreach (PreferredContainer preferredContainer in itemPrefab.PreferredContainers) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs index 8f801b9e3..a54a51da5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSettings.cs @@ -907,6 +907,7 @@ namespace Barotrauma new XAttribute("width", GraphicsWidth), new XAttribute("height", GraphicsHeight), new XAttribute("vsync", VSyncEnabled), + new XAttribute("framelimit", Timing.FrameLimit), new XAttribute("displaymode", windowMode)); } @@ -1228,6 +1229,7 @@ namespace Barotrauma new XAttribute("width", GraphicsWidth), new XAttribute("height", GraphicsHeight), new XAttribute("vsync", VSyncEnabled), + new XAttribute("framelimit", Timing.FrameLimit), new XAttribute("displaymode", windowMode)); } @@ -1423,6 +1425,7 @@ namespace Barotrauma GraphicsWidth = graphicsMode.GetAttributeInt("width", GraphicsWidth); GraphicsHeight = graphicsMode.GetAttributeInt("height", GraphicsHeight); VSyncEnabled = graphicsMode.GetAttributeBool("vsync", VSyncEnabled); + Timing.FrameLimit = graphicsMode.GetAttributeInt("framelimit", 200); XElement graphicsSettings = doc.Root.Element("graphicssettings"); ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", ParticleLimit); @@ -1504,6 +1507,7 @@ namespace Barotrauma GraphicsWidth = 0; GraphicsHeight = 0; VSyncEnabled = true; + Timing.FrameLimit = 200; #if DEBUG EnableSplashScreen = false; #else diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 8028855bb..14712fe12 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1283,7 +1283,7 @@ namespace Barotrauma } } - ApplyStatusEffects(ActionType.Always, deltaTime, null); + ApplyStatusEffects(ActionType.Always, deltaTime, character: (parentInventory as CharacterInventory)?.Owner as Character); for (int i = 0; i < updateableComponents.Count; i++) { @@ -1306,7 +1306,7 @@ namespace Barotrauma #endif ic.WasUsed = false; - ic.ApplyStatusEffects(parentInventory == null ? ActionType.OnNotContained : ActionType.OnContained, deltaTime); + ic.ApplyStatusEffects(parentInventory == null ? ActionType.OnNotContained : ActionType.OnContained, deltaTime, character: (parentInventory as CharacterInventory)?.Owner as Character); if (ic.IsActive) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs index b0d3c4683..27ca4a39a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs @@ -228,7 +228,9 @@ namespace Barotrauma if (hulls[i] == null) hulls[i] = Hull.FindHullOld(searchPos[i], null, false, true); } - if (hulls[0] == null && hulls[1] == null) return; + if (hulls[1] == hulls[0]) { hulls[1] = null; } + + if (hulls[0] == null && hulls[1] == null) { return; } if (hulls[0] == null && hulls[1] != null) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs index fe9abe34d..fb11526b5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Structure.cs @@ -619,7 +619,10 @@ namespace Barotrauma if (Bodies != null) { foreach (Body b in Bodies) + { GameMain.World.Remove(b); + } + Bodies.Clear(); } if (Sections != null) @@ -648,7 +651,10 @@ namespace Barotrauma if (Bodies != null) { foreach (Body b in Bodies) + { GameMain.World.Remove(b); + } + Bodies.Clear(); } if (Sections != null) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs index 8a87b93cc..e0990e3f0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs @@ -14,6 +14,7 @@ namespace Barotrauma.Networking private static Stream writeStream; private static Stream readStream; private static volatile bool shutDown; + private static ManualResetEvent writeManualResetEvent; private static byte[] tempBytes; private enum ReadState @@ -49,6 +50,8 @@ namespace Barotrauma.Networking readCancellationToken = new CancellationTokenSource(); + writeManualResetEvent = new ManualResetEvent(false); + readThread = new Thread(UpdateRead); writeThread = new Thread(UpdateWrite); readThread.Start(); @@ -58,6 +61,7 @@ namespace Barotrauma.Networking private static void PrivateShutDown() { shutDown = true; + writeManualResetEvent.Set(); readCancellationToken?.Cancel(); readThread?.Join(); readThread = null; writeThread?.Join(); writeThread = null; @@ -152,7 +156,11 @@ namespace Barotrauma.Networking msgAvailable = msgsToWrite.TryDequeue(out msg); } } - Thread.Yield(); + if (!shutDown) + { + writeManualResetEvent.Reset(); + writeManualResetEvent.WaitOne(); + } } } @@ -163,6 +171,7 @@ namespace Barotrauma.Networking lock (msgsToWrite) { msgsToWrite.Enqueue(msg); + writeManualResetEvent.Set(); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerLog.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerLog.cs index a3255d9fe..d656a8baf 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerLog.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/ServerLog.cs @@ -154,10 +154,16 @@ namespace Barotrauma.Networking } } - string fileName = ServerName + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH:mm") + ".txt"; + string fileName = ServerName + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH:mm"); fileName = ToolBox.RemoveInvalidFileNameChars(fileName); - string filePath = Path.Combine(SavePath, fileName); + string filePath = Path.Combine(SavePath, fileName + ".txt"); + int i = 2; + while (File.Exists(filePath)) + { + filePath = Path.Combine(SavePath, fileName + " (" + i + ").txt"); + i++; + } try { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs index 0ad827dc9..a4b1656fe 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/Screen.cs @@ -20,10 +20,12 @@ public virtual void Select() { + if (selected != null && selected != this) { selected.Deselect(); #if CLIENT + GUI.ClearCursorWait(); //make sure any textbox in the previously selected screen doesn't stay selected if (GUI.KeyboardDispatcher.Subscriber != DebugConsole.TextBox) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Timing.cs b/Barotrauma/BarotraumaShared/SharedSource/Timing.cs index 6e670dcfb..c8b59b590 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Timing.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Timing.cs @@ -10,7 +10,28 @@ namespace Barotrauma public static double TotalTime; public static double Accumulator; - public static double Step = 1.0 / 60.0; + public const int FixedUpdateRate = 60; + public static double Step = 1.0 / FixedUpdateRate; + + private static int frameLimit; + /// + /// Maximum FPS (0 = unlimited). + /// + public static int FrameLimit + { + get { return frameLimit; } + set + { + if (value <= 0) + { + frameLimit = 0; + } + else + { + frameLimit = Math.Max(value, FixedUpdateRate); + } + } + } public static double Alpha { diff --git a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub index 59b97e680..b1bb8a801 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub and b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub index c18c787ce..eedff8171 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Humpback.sub and b/Barotrauma/BarotraumaShared/Submarines/Humpback.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub index 427c7085a..51607364c 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon2.sub differ diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 1ba1ebc2b..44c564ebf 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,5 +1,25 @@ --------------------------------------------------------------------------------------------------------- -v0.9.7000 (Unstable) +v0.9.701 (Unstable) +--------------------------------------------------------------------------------------------------------- + +- Fixed SteamP2P server hosting. +- Fixed a bug that caused "missing entity" errors when joining mid-round. Occurred if entities were created or removed while the client was in the process of getting in sync with the server, for example if the other players were firing turrets while the client was joining. However, there may still other bugs left that can cause the same "missing entity" error message. +- Cap the framerate to 200 FPS when VSync is off to prevent overloading the GPU. The cap can be adjusted by changing the "framelimit" attribute in config_player.xml. +- Rebalanced random events. +- Numerous fixes and improvements to Berilia. +- Give job items to humans spawned with the "spawn" command. +- Fixed content package hash mismatches between Windows and Linux. +- Fixed client crashing when disconnecting from the server as a host. +- Fixed clients crashing when an order message is received while in the server lobby. +- New sprites (that actually match the worn sprite) for dropped outfits. +- Slightly increased the view range of the coilguns and railguns. +- Cursor changes according to what it's hovered on (hand icon when on a button, caret icon when on a textbox, etc). +- The automatically placed items are not listed in the debug console by default anymore. Listing them can be re-enabled with the command "outfitdebug". +- Fixed crashing when saving structures into item assemblies. +- Fixed sub editor allowing vanilla subs to be deleted. + +--------------------------------------------------------------------------------------------------------- +v0.9.700 (Unstable) --------------------------------------------------------------------------------------------------------- - Additional logging to diagnose event/entity ID errors: server and clients write a log file with a bunch of debug information the error happens. The files can be found in the ServerLogs folder after the error has occurred. If you get log files, please send them to us to help us diagnose these bugs! @@ -24,10 +44,12 @@ v0.9.7.0 --------------------------------------------------------------------------------------------------------- UI/UX improvements: +- Graphical and functional overhaul of all user interfaces. +- Better feedback on shooting. - Double clicking on an item moves it to the equipped inventory (e.g. ammo to the equipped weapon). - Periscopes can be deselected by pressing esc. - Fabricators can pull ingredients directly from the user's inventory without having to place them in the fabricator's input slots. -- Lock the on/off slider in the pump interface when the state is controlled by signals, same with the engine slider. +- Lock the on/off switch in the pump interface when the state is controlled by signals, same with the engine slider. - 1 second cooldown before doors can be opened/closed after someone else has opened/closed them. Makes it less likely for doors to be opened/closed accidentally when multiple people are trying to use them at the same time. - Show a warning if trying to start a campaign for the first time without playing the tutorials. - Diving suits and fire extinguishers are not automatically picked up from the lockers/brackets when clicking on them to make it less likely to accidentally pick them up. Instead, clicking on them opens the inventory of the container, the same way when interacting with e.g. a steel cabinet. @@ -58,7 +80,7 @@ Additions and changes: - The job gear variants are not just visually different versions of the same item, but completely separate items. The job variants now allow the players to choose what kind of gear they want to spawn with, not just the look of the uniform. - Attachable items and wire nodes can now be freely placed around the character instead of always being placed at the position of the character. When attaching items/wires, there's a placement grid that makes it much easier to neatly attach/wire things mid-round. - The submarines now get automatically outfitted with a semi-random selection of supplies when starting a campaign. The items that have been manually placed in the submarine editor are kept as-is. -- Split internal damage into multiple subtypes: blunt force trauma, lacerations and bite wounds. The new afflictions are functionally identical to the default internal damage affliction, but can be used to identify the source of the injuries. +- Splitted internal damage into multiple subtypes: blunt force trauma, lacerations and bite wounds. The new afflictions are functionally identical to the default internal damage affliction, but can be used to identify the source of the injuries. - Humans are more resistant to gunshot wounds, lacerations and blunt force trauma than monsters. The intention is to allow making weapons more effective towards monsters without making killing your crewmates with them too easy. - Added a "terminal" item that can be used to send and display textual signals. Could be used for things such as terminals that send commands to devices or display some data received from devices. - Added muzzle flashes to small firearms. diff --git a/Libraries/Farseer Physics Engine 3.5/Dynamics/Body.cs b/Libraries/Farseer Physics Engine 3.5/Dynamics/Body.cs index 63587f0de..a5faa3177 100644 --- a/Libraries/Farseer Physics Engine 3.5/Dynamics/Body.cs +++ b/Libraries/Farseer Physics Engine 3.5/Dynamics/Body.cs @@ -82,8 +82,8 @@ namespace FarseerPhysics.Dynamics BodyType = BodyType.Static; } - public World World { get {return _world; } } - + public World World { get { return _world; } } + public int IslandIndex { get; set; } /// @@ -350,7 +350,17 @@ namespace FarseerPhysics.Dynamics /// Create all proxies. /// internal void CreateProxies() - { + { + for (int i = 0; i < FixtureList.Count; i++) + { + Debug.Assert(FixtureList[i].ProxyCount == 0, "Proxies already created for a Fixture."); + if (FixtureList[i].ProxyCount > 0) + { + DestroyProxies(); + break; + } + } + IBroadPhase broadPhase = World.ContactManager.BroadPhase; for (int i = 0; i < FixtureList.Count; i++) FixtureList[i].CreateProxies(broadPhase, ref _xf); diff --git a/Libraries/Farseer Physics Engine 3.5/Dynamics/Fixture.cs b/Libraries/Farseer Physics Engine 3.5/Dynamics/Fixture.cs index d3da06c69..40381f0d4 100644 --- a/Libraries/Farseer Physics Engine 3.5/Dynamics/Fixture.cs +++ b/Libraries/Farseer Physics Engine 3.5/Dynamics/Fixture.cs @@ -307,7 +307,7 @@ namespace FarseerPhysics.Dynamics internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf) { if (ProxyCount != 0) - throw new InvalidOperationException("Proxies allready created for this Fixture."); + throw new InvalidOperationException("Proxies already created for this Fixture."); // Create proxies in the broad-phase. ProxyCount = Shape.ChildCount;