(2402e736e) Tester's build, January 25th 2020

This commit is contained in:
Joonas Rikkonen
2020-01-25 12:48:13 +02:00
parent 4a58987eae
commit eaa18a20a3
57 changed files with 710 additions and 139 deletions
-3
View File
@@ -13,9 +13,6 @@ bld/
[Rr]elease*/ [Rr]elease*/
*.o *.o
# Barotrauma content folder
BarotraumaShared/Content/
# Misc vs crap # Misc vs crap
*.v12.suo *.v12.suo
*.suo *.suo
@@ -176,6 +176,8 @@ namespace Barotrauma
healthBar = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas), healthBar = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas),
barSize: 1.0f, color: Color.Green, style: horizontal ? "GUIProgressBar" : "GUIProgressBarVertical") barSize: 1.0f, color: Color.Green, style: horizontal ? "GUIProgressBar" : "GUIProgressBarVertical")
{ {
Enabled = true,
HoverCursor = CursorState.Hand,
IsHorizontal = horizontal IsHorizontal = horizontal
}; };
healthBarShadow = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas), healthBarShadow = new GUIProgressBar(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.HealthBarAreaLeft, GUI.Canvas),
@@ -26,17 +26,14 @@ namespace Barotrauma
/// <seealso cref="NetLobbyScreen.Select"/> where I'm utilizing this /// <seealso cref="NetLobbyScreen.Select"/> where I'm utilizing this
private readonly List<GUITextBox> registers = new List<GUITextBox>(); private readonly List<GUITextBox> registers = new List<GUITextBox>();
private readonly bool skipDuplicate;
// Selector index // Selector index
private int index; private int index;
// Local changes we've made into previously stored messages // Local changes we've made into previously stored messages
private string[] localChanges; private string[] localChanges;
public ChatManager(bool skipDuplicate, bool loop, short maxCount) public ChatManager(bool loop, short maxCount)
{ {
this.skipDuplicate = skipDuplicate;
this.loop = loop; this.loop = loop;
this.maxCount = maxCount; this.maxCount = maxCount;
localChanges = new string[maxCount]; localChanges = new string[maxCount];
@@ -87,13 +84,10 @@ namespace Barotrauma
public void Store(string message) public void Store(string message)
{ {
Clear(); Clear();
string strip = StripMessage(message); var strip = StripMessage(message);
if (string.IsNullOrWhiteSpace(strip)) { return; } if (string.IsNullOrWhiteSpace(strip)) { return; }
if (skipDuplicate && messageList.Any(p => message == p)) if (messageList.Count > 1 && messageList[1] == message) { return; }
{
return;
}
// insert to the second position as the first position is reserved for the original message if any // insert to the second position as the first position is reserved for the original message if any
messageList.Insert(1, message); 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);] // [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); ChatMessage.GetChatMessageCommand(text, out string msg);
return msg; return msg;
@@ -129,40 +123,61 @@ namespace Barotrauma
/// <returns>A message or null</returns> /// <returns>A message or null</returns>
private string SelectMessage(Direction direction, string original) private string SelectMessage(Direction direction, string original)
{ {
if (direction == Direction.Other) { return null; } var originalIndex = index;
while (true)
// 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)
{ {
nextIndex = LoopAround(nextIndex); if (direction == Direction.Other)
}
else
{
if (nextIndex > messageList.Count - 1)
{ {
return null; 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) // temporarily save our changes in case we fat-finger and want to go back
{ localChanges[index] = original;
if (next > (messageList.Count - 1)) { return 1; }
if (next < 1) { return messageList.Count - 1; } var dir = (int) direction;
return next;
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;
}
} }
} }
@@ -61,7 +61,7 @@ namespace Barotrauma
public static GUITextBox TextBox => textBox; 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() public static void Init()
{ {
@@ -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.CharacterEditor;
using Barotrauma.Extensions; using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking; using Barotrauma.Networking;
using Barotrauma.Sounds; using Barotrauma.Sounds;
using Barotrauma.Tutorials;
using EventInput; using EventInput;
using FarseerPhysics; using FarseerPhysics;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma namespace Barotrauma
{ {
@@ -26,11 +28,23 @@ namespace Barotrauma
PickItemFail, PickItemFail,
DropItem 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 class GUI
{ {
public static GUICanvas Canvas => GUICanvas.Instance; public static GUICanvas Canvas => GUICanvas.Instance;
public static CursorState MouseCursor = CursorState.Default;
public static readonly SamplerState SamplerState = new SamplerState() public static readonly SamplerState SamplerState = new SamplerState()
{ {
Filter = TextureFilter.Linear, Filter = TextureFilter.Linear,
@@ -82,8 +96,7 @@ namespace Barotrauma
public static GUIStyle Style; public static GUIStyle Style;
private static Texture2D t; private static Texture2D t;
private static Sprite[] MouseCursorSprites => Style.CursorSprite;
private static Sprite Cursor => Style.CursorSprite;
private static bool debugDrawSounds, debugDrawEvents; private static bool debugDrawSounds, debugDrawEvents;
@@ -184,7 +197,7 @@ namespace Barotrauma
public static void Init(GameWindow window, IEnumerable<ContentPackage> selectedContentPackages, GraphicsDevice graphicsDevice) public static void Init(GameWindow window, IEnumerable<ContentPackage> selectedContentPackages, GraphicsDevice graphicsDevice)
{ {
GUI.GraphicsDevice = graphicsDevice; GraphicsDevice = graphicsDevice;
var files = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle); var files = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle);
XElement selectedStyle = null; XElement selectedStyle = null;
@@ -306,7 +319,7 @@ namespace Barotrauma
if (GameMain.ShowFPS || GameMain.DebugDraw) if (GameMain.ShowFPS || GameMain.DebugDraw)
{ {
DrawString(spriteBatch, new Vector2(10, 10), 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); Color.White, Color.Black * 0.5f, 0, SmallFont);
} }
@@ -339,7 +352,7 @@ namespace Barotrauma
y += 15; 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), "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); 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 else
{ {
soundStr += System.IO.Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename); soundStr += Path.GetFileNameWithoutExtension(playingSoundChannel.Sound.Filename);
#if DEBUG #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) if (PlayerInput.MousePosition.Y >= y && PlayerInput.MousePosition.Y <= y + 12)
{ {
@@ -507,10 +520,13 @@ namespace Barotrauma
if (GameMain.WindowActive && !HideCursor) if (GameMain.WindowActive && !HideCursor)
{ {
spriteBatch.End(); spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable); spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
Cursor.Draw(spriteBatch, PlayerInput.LatestMousePosition, 0, Scale / 2f);
var sprite = MouseCursorSprites[(int) MouseCursor];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End(); spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable); spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
} }
HideCursor = false; HideCursor = false;
} }
@@ -723,13 +739,14 @@ namespace Barotrauma
GUIComponent prevMouseOn = MouseOn; GUIComponent prevMouseOn = MouseOn;
MouseOn = null; MouseOn = null;
int inventoryIndex = -1; int inventoryIndex = -1;
if (Inventory.IsMouseOnInventory()) if (Inventory.IsMouseOnInventory())
{ {
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame); 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.CanBeFocused) { continue; }
if (c.MouseRect.Contains(PlayerInput.MousePosition)) if (c.MouseRect.Contains(PlayerInput.MousePosition))
{ {
@@ -740,8 +757,198 @@ namespace Barotrauma
break; break;
} }
} }
MouseCursor = UpdateMouseCursorState(MouseOn);
return 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);
}
}
/// <summary>
/// Set the cursor to an hourglass.
/// Will automatically revert after 10 seconds or when <see cref="ClearCursorWait"/> is called.
/// </summary>
public static void SetCursorWaiting()
{
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
static IEnumerable<object> 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) public static bool HasSizeChanged(Point referenceResolution, float referenceUIScale, float referenceHUDScale)
{ {
@@ -754,7 +961,7 @@ namespace Barotrauma
HandlePersistingElements(deltaTime); HandlePersistingElements(deltaTime);
RefreshUpdateList(); RefreshUpdateList();
UpdateMouseOn(); UpdateMouseOn();
System.Diagnostics.Debug.Assert(updateList.Count == updateListSet.Count); Debug.Assert(updateList.Count == updateListSet.Count);
updateList.ForEach(c => c.UpdateAuto(deltaTime)); updateList.ForEach(c => c.UpdateAuto(deltaTime));
UpdateMessages(deltaTime); UpdateMessages(deltaTime);
} }
@@ -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) public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null, ScalableFont font = null) : base(style, rectT)
{ {
CanBeFocused = true; CanBeFocused = true;
HoverCursor = CursorState.Hand;
if (color.HasValue) if (color.HasValue)
{ {
@@ -16,6 +16,8 @@ namespace Barotrauma
#region Hierarchy #region Hierarchy
public GUIComponent Parent => RectTransform.Parent?.GUIComponent; public GUIComponent Parent => RectTransform.Parent?.GUIComponent;
public CursorState HoverCursor = CursorState.Default;
public IEnumerable<GUIComponent> Children => RectTransform.Children.Select(c => c.GUIComponent); public IEnumerable<GUIComponent> Children => RectTransform.Children.Select(c => c.GUIComponent);
public T GetChild<T>() where T : GUIComponent public T GetChild<T>() where T : GUIComponent
@@ -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) 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; CanBeFocused = true;
this.selectMultiple = selectMultiple; this.selectMultiple = selectMultiple;
@@ -192,12 +192,28 @@ namespace Barotrauma
public GUIScrollBar(RectTransform rectT, float barSize = 1, Color? color = null, string style = "", bool? isHorizontal = null) : base(style, rectT) public GUIScrollBar(RectTransform rectT, float barSize = 1, Color? color = null, string style = "", bool? isHorizontal = null) : base(style, rectT)
{ {
CanBeFocused = true; CanBeFocused = true;
this.isHorizontal = isHorizontal ?? (Rect.Width > Rect.Height); this.isHorizontal = isHorizontal ?? (Rect.Width > Rect.Height);
Frame = new GUIFrame(new RectTransform(Vector2.One, rectT)); Frame = new GUIFrame(new RectTransform(Vector2.One, rectT));
GUI.Style.Apply(Frame, IsHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this); GUI.Style.Apply(Frame, IsHorizontal ? "GUIFrameHorizontal" : "GUIFrameVertical", this);
this.barSize = barSize; this.barSize = barSize;
Bar = new GUIButton(new RectTransform(Vector2.One, rectT, IsHorizontal ? Anchor.CenterLeft : Anchor.TopCenter), color: color); 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); GUI.Style.Apply(Bar, IsHorizontal ? "GUIButtonHorizontal" : "GUIButtonVertical", this);
Bar.OnPressed = SelectBar; Bar.OnPressed = SelectBar;
enabled = true; enabled = true;
@@ -222,8 +238,6 @@ namespace Barotrauma
{ {
if (!Visible) { return; } if (!Visible) { return; }
base.Update(deltaTime);
if (!enabled) { return; } if (!enabled) { return; }
Frame.State = GUI.MouseOn == Frame ? ComponentState.Hover : ComponentState.None; Frame.State = GUI.MouseOn == Frame ? ComponentState.Hover : ComponentState.None;
@@ -25,7 +25,7 @@ namespace Barotrauma
public ScalableFont ObjectiveTitleFont { get; private set; } public ScalableFont ObjectiveTitleFont { get; private set; }
public ScalableFont ObjectiveNameFont { 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; } public UISprite UIGlow { get; private set; }
@@ -38,10 +38,15 @@ namespace Barotrauma
configElement = element; configElement = element;
foreach (XElement subElement in configElement.Elements()) foreach (XElement subElement in configElement.Elements())
{ {
switch (subElement.Name.ToString().ToLowerInvariant()) var name = subElement.Name.ToString().ToLowerInvariant();
switch (name)
{ {
case "cursor": 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; break;
case "uiglow": case "uiglow":
UIGlow = new UISprite(subElement); UIGlow = new UISprite(subElement);
@@ -231,6 +231,7 @@ namespace Barotrauma
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null) Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
: base(style, rectT) : base(style, rectT)
{ {
HoverCursor = CursorState.IBeam;
CanBeFocused = true; CanBeFocused = true;
Enabled = true; Enabled = true;
@@ -134,6 +134,7 @@ namespace Barotrauma
public GUITickBox(RectTransform rectT, string label, ScalableFont font = null, string style = "") : base(null, rectT) public GUITickBox(RectTransform rectT, string label, ScalableFont font = null, string style = "") : base(null, rectT)
{ {
CanBeFocused = true; CanBeFocused = true;
HoverCursor = CursorState.Hand;
layoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), true); layoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), true);
@@ -176,6 +177,7 @@ namespace Barotrauma
protected override void Update(float deltaTime) protected override void Update(float deltaTime)
{ {
if (!Visible) return; if (!Visible) return;
base.Update(deltaTime);
if (GUI.MouseOn == this && Enabled) if (GUI.MouseOn == this && Enabled)
{ {
@@ -891,7 +891,13 @@ namespace Barotrauma
double deltaTime = gameTime.ElapsedGameTime.TotalSeconds; 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) if (loadingScreenOpen)
{ {
@@ -97,7 +97,10 @@ namespace Barotrauma.Tutorials
stunbaton.Unequip(officer); stunbaton.Unequip(officer);
officer.Inventory.RemoveItem(stunbaton); 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); ballistichelmet.Unequip(officer);
officer.Inventory.RemoveItem(ballistichelmet); officer.Inventory.RemoveItem(ballistichelmet);
@@ -24,6 +24,12 @@ namespace Barotrauma.Items.Components
{ {
get { return flashTimer; } get { return flashTimer; }
} }
public static Wire DraggingConnected
{
get => draggingConnected;
}
private float flashTimer; private float flashTimer;
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character) public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
@@ -51,6 +51,11 @@ namespace Barotrauma.Items.Components
get { return sectionExtents; } get { return sectionExtents; }
} }
public static Wire DraggingWire
{
get => draggingWire;
}
partial void InitProjSpecific(XElement element) partial void InitProjSpecific(XElement element)
{ {
if (defaultWireSprite == null) if (defaultWireSprite == null)
@@ -653,10 +653,19 @@ namespace Barotrauma
if (Character.Controlled.Inventory != null) 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) || var slot = inv.slots[i];
slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) 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; return true;
} }
@@ -664,10 +673,19 @@ namespace Barotrauma
} }
if (Character.Controlled.SelectedCharacter?.Inventory != null) 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) || var slot = inv.slots[i];
slot.EquipButtonRect.Contains(PlayerInput.MousePosition)) 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; return true;
} }
@@ -676,7 +694,7 @@ namespace Barotrauma
if (Character.Controlled.SelectedConstruction != null) 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; var itemContainer = ic as ItemContainer;
if (itemContainer?.Inventory?.slots == null) continue; if (itemContainer?.Inventory?.slots == null) continue;
@@ -699,6 +717,88 @@ namespace Barotrauma
return false; 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<ItemContainer>();
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> colorData = null) protected static void DrawToolTip(SpriteBatch spriteBatch, string toolTip, Rectangle highlightedSlot, List<ColorData> colorData = null)
{ {
@@ -88,8 +88,15 @@ namespace Barotrauma
float arrowWidth = 32.0f; float arrowWidth = 32.0f;
float arrowSize = 15.0f; float arrowSize = 15.0f;
bool invalidDir = false;
if (dir == Vector2.Zero)
{
invalidDir = true;
dir = IsHorizontal ? Vector2.UnitX : Vector2.UnitY;
}
GUI.Arrow.Draw(sb, GUI.Arrow.Draw(sb,
arrowPos, clr * 0.8f, arrowPos, invalidDir ? Color.Red : clr * 0.8f,
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2, GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
IsHorizontal ? IsHorizontal ?
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) : new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) :
@@ -44,6 +44,8 @@ namespace Barotrauma
private Location highlightedLocation; private Location highlightedLocation;
public Location HighlightedLocation => highlightedLocation;
private Vector2 drawOffset; private Vector2 drawOffset;
private Vector2 drawOffsetNoise; private Vector2 drawOffsetNoise;
@@ -13,7 +13,9 @@ namespace Barotrauma
protected static Vector2 selectionPos = Vector2.Zero; protected static Vector2 selectionPos = Vector2.Zero;
protected static Vector2 selectionSize = 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 static bool resizing;
private int resizeDirX, resizeDirY; private int resizeDirX, resizeDirY;
@@ -66,7 +66,7 @@ namespace Barotrauma.Networking
} }
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption); 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) if (order.TargetAllCharacters)
{ {
@@ -401,6 +401,7 @@ namespace Barotrauma.Networking
// Before main looping starts, we loop here and wait for approval message // Before main looping starts, we loop here and wait for approval message
private IEnumerable<object> WaitForStartingInfo() private IEnumerable<object> WaitForStartingInfo()
{ {
GUI.SetCursorWaiting();
requiresPw = false; requiresPw = false;
pwRetries = -1; pwRetries = -1;
@@ -503,6 +504,7 @@ namespace Barotrauma.Networking
reconnectBox?.Close(); reconnectBox = null; reconnectBox?.Close(); reconnectBox = null;
GUI.ClearCursorWait();
if (connectCancelled) { yield return CoroutineStatus.Success; } if (connectCancelled) { yield return CoroutineStatus.Success; }
yield return CoroutineStatus.Success; yield return CoroutineStatus.Success;
@@ -1435,6 +1437,11 @@ namespace Barotrauma.Networking
if (clientPeer is SteamP2POwnerPeer) if (clientPeer is SteamP2POwnerPeer)
{ {
TaskPool.Add(Steamworks.SteamNetworkingUtils.WaitForPingDataAsync(), (task) =>
{
Steam.SteamManager.UpdateLobby(serverSettings);
});
Steam.SteamManager.UpdateLobby(serverSettings); Steam.SteamManager.UpdateLobby(serverSettings);
} }
} }
@@ -1978,7 +1985,7 @@ namespace Barotrauma.Networking
if (ChildServerRelay.Process != null) if (ChildServerRelay.Process != null)
{ {
int checks = 0; int checks = 0;
while (!ChildServerRelay.Process.HasExited) while (ChildServerRelay.Process != null && !ChildServerRelay.Process.HasExited)
{ {
if (checks > 10) if (checks > 10)
{ {
@@ -509,11 +509,6 @@ namespace Barotrauma.Networking
IP = ""; IP = "";
Port = ""; Port = "";
QueryPort = ""; QueryPort = "";
string pingLocation = lobby.GetData("pinglocation");
if (!string.IsNullOrEmpty(pingLocation))
{
PingLocation = Steamworks.Data.PingLocation.TryParseFromString(pingLocation);
}
PlayerCount = currPlayers; PlayerCount = currPlayers;
MaxPlayers = maxPlayers; MaxPlayers = maxPlayers;
HasPassword = hasPassword; HasPassword = hasPassword;
@@ -118,6 +118,8 @@ namespace Barotrauma.Steam
TaskPool.Add(Steamworks.SteamMatchmaking.CreateLobbyAsync(serverSettings.MaxPlayers + 10), TaskPool.Add(Steamworks.SteamMatchmaking.CreateLobbyAsync(serverSettings.MaxPlayers + 10),
(lobby) => (lobby) =>
{ {
currentLobby = lobby.Result;
if (currentLobby == null) if (currentLobby == null)
{ {
DebugConsole.ThrowError("Failed to create Steam lobby"); DebugConsole.ThrowError("Failed to create Steam lobby");
@@ -125,8 +127,6 @@ namespace Barotrauma.Steam
return; return;
} }
currentLobby = lobby.Result;
DebugConsole.NewMessage("Lobby created!", Microsoft.Xna.Framework.Color.Lime); DebugConsole.NewMessage("Lobby created!", Microsoft.Xna.Framework.Color.Lime);
lobbyState = LobbyState.Owner; lobbyState = LobbyState.Owner;
@@ -169,7 +169,8 @@ namespace Barotrauma.Steam
currentLobby?.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count ?? 0).ToString()); currentLobby?.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count ?? 0).ToString());
currentLobby?.SetData("maxplayernum", serverSettings.MaxPlayers.ToString()); currentLobby?.SetData("maxplayernum", serverSettings.MaxPlayers.ToString());
//currentLobby?.SetData("hostipaddress", lobbyIP); //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("lobbyowner", SteamIDUInt64ToString(GetSteamID()));
currentLobby?.SetData("haspassword", serverSettings.HasPassword.ToString()); currentLobby?.SetData("haspassword", serverSettings.HasPassword.ToString());
@@ -254,6 +255,7 @@ namespace Barotrauma.Steam
ServerInfo serverInfo = new ServerInfo(); ServerInfo serverInfo = new ServerInfo();
serverInfo.ServerName = lobby.GetData("name"); serverInfo.ServerName = lobby.GetData("name");
serverInfo.OwnerID = SteamIDStringToUInt64(lobby.GetData("lobbyowner"));
serverInfo.LobbyID = lobby.Id; serverInfo.LobbyID = lobby.Id;
serverInfo.PlayerCount = int.TryParse(lobby.GetData("playercount"), out int playerCount) ? playerCount : 0; serverInfo.PlayerCount = int.TryParse(lobby.GetData("playercount"), out int playerCount) ? playerCount : 0;
serverInfo.MaxPlayers = int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers) ? maxPlayers : 1; serverInfo.MaxPlayers = int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers) ? maxPlayers : 1;
@@ -371,6 +373,12 @@ namespace Barotrauma.Steam
serverInfo.ContentPackageHashes.Clear(); serverInfo.ContentPackageHashes.Clear();
} }
string pingLocation = lobby.GetData("pinglocation");
if (!string.IsNullOrEmpty(pingLocation))
{
serverInfo.PingLocation = Steamworks.Data.PingLocation.TryParseFromString(pingLocation);
}
bool? getLobbyBool(string key) bool? getLobbyBool(string key)
{ {
string data = lobby.GetData(key); string data = lobby.GetData(key);
@@ -112,6 +112,7 @@ namespace Barotrauma
if (GameMain.Config != null) if (GameMain.Config != null)
{ {
sb.AppendLine("Graphics mode: " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight + " (" + GameMain.Config.WindowMode.ToString() + ")"); 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) if (GameMain.SelectedPackages != null)
{ {
@@ -244,6 +244,7 @@ namespace Barotrauma
private IEnumerable<object> WaitForCampaignSetup() private IEnumerable<object> WaitForCampaignSetup()
{ {
GUI.SetCursorWaiting();
string headerText = TextManager.Get("CampaignStartingPleaseWait"); string headerText = TextManager.Get("CampaignStartingPleaseWait");
var msgBox = new GUIMessageBox(headerText, TextManager.Get("CampaignStarting"), new string[] { TextManager.Get("Cancel") }); 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.HighlightMode(GameMain.NetLobbyScreen.SelectedModeIndex);
GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex); GameMain.NetLobbyScreen.SelectMode(GameMain.NetLobbyScreen.SelectedModeIndex);
GUI.ClearCursorWait();
CoroutineManager.StopCoroutines("WaitForCampaignSetup"); CoroutineManager.StopCoroutines("WaitForCampaignSetup");
return true; return true;
}; };
@@ -263,6 +265,7 @@ namespace Barotrauma
yield return CoroutineStatus.Running; yield return CoroutineStatus.Running;
} }
msgBox.Close(); msgBox.Close();
GUI.ClearCursorWait();
yield return CoroutineStatus.Success; yield return CoroutineStatus.Success;
} }
@@ -746,6 +746,21 @@ namespace Barotrauma.CharacterEditor
buttonsPanelToggle?.UpdateOpenState((float)deltaTime, new Vector2(-buttonsPanel.Rect.Width - leftArea.RectTransform.AbsoluteOffset.X, 0), buttonsPanel.RectTransform); 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;
}
/// <summary> /// <summary>
/// Fps independent mouse input. The draw method is called multiple times per frame. /// Fps independent mouse input. The draw method is called multiple times per frame.
/// </summary> /// </summary>
@@ -18,6 +18,11 @@ namespace Barotrauma
get { return GameMain.GameSession.CrewManager; } get { return GameMain.GameSession.CrewManager; }
} }
public CampaignUI CampaignUI
{
get { return campaignUI; }
}
public string GetMoney() public string GetMoney()
{ {
return campaignUI == null ? "" : campaignUI.GetMoney(); return campaignUI == null ? "" : campaignUI.GetMoney();
@@ -545,10 +545,10 @@ namespace Barotrauma
break; break;
case Tab.CharacterEditor: case Tab.CharacterEditor:
Submarine.MainSub = null; Submarine.MainSub = null;
GameMain.CharacterEditorScreen.Select(); CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.CharacterEditorScreen));
break; break;
case Tab.SubmarineEditor: case Tab.SubmarineEditor:
GameMain.SubEditorScreen.Select(); CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.SubEditorScreen));
break; break;
case Tab.QuickStartDev: case Tab.QuickStartDev:
QuickStart(); QuickStart();
@@ -560,7 +560,7 @@ namespace Barotrauma
break; break;
case Tab.SteamWorkshop: case Tab.SteamWorkshop:
if (!Steam.SteamManager.IsInitialized) return false; if (!Steam.SteamManager.IsInitialized) return false;
GameMain.SteamWorkshopScreen.Select(); CoroutineManager.StartCoroutine(SelectScreenWithWaitCursor(GameMain.SteamWorkshopScreen));
break; break;
case Tab.Credits: case Tab.Credits:
titleText.Visible = false; titleText.Visible = false;
@@ -577,6 +577,16 @@ namespace Barotrauma
return true; return true;
} }
private IEnumerable<object> 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) public bool ReturnToMainMenu(GUIButton button, object obj)
{ {
GUI.PreventPauseMenuToggle = false; 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) maxPlayersBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform), textAlignment: Alignment.Center)
{ {
Text = maxPlayers.ToString(), Text = maxPlayers.ToString(),
Enabled = false // ?
// Enabled = false
}; };
new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform), "+", textAlignment: Alignment.Center) new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform), "+", textAlignment: Alignment.Center)
{ {
@@ -1080,6 +1080,7 @@ namespace Barotrauma
public IEnumerable<object> WaitForStartRound(GUIButton startButton, bool allowCancel) public IEnumerable<object> WaitForStartRound(GUIButton startButton, bool allowCancel)
{ {
GUI.SetCursorWaiting();
string headerText = TextManager.Get("RoundStartingPleaseWait"); string headerText = TextManager.Get("RoundStartingPleaseWait");
var msgBox = new GUIMessageBox(headerText, TextManager.Get("RoundStarting"), var msgBox = new GUIMessageBox(headerText, TextManager.Get("RoundStarting"),
allowCancel ? new string[] { TextManager.Get("Cancel") } : new string[0]); allowCancel ? new string[] { TextManager.Get("Cancel") } : new string[0]);
@@ -1091,6 +1092,7 @@ namespace Barotrauma
startButton.Enabled = true; startButton.Enabled = true;
GameMain.Client.RequestRoundEnd(); GameMain.Client.RequestRoundEnd();
CoroutineManager.StopCoroutines("WaitForStartRound"); CoroutineManager.StopCoroutines("WaitForStartRound");
GUI.ClearCursorWait();
return true; return true;
}; };
msgBox.Buttons[0].OnClicked += msgBox.Close; msgBox.Buttons[0].OnClicked += msgBox.Close;
@@ -1113,7 +1115,7 @@ namespace Barotrauma
{ {
startButton.Enabled = true; startButton.Enabled = true;
} }
GUI.ClearCursorWait();
yield return CoroutineStatus.Success; yield return CoroutineStatus.Success;
} }
@@ -147,6 +147,8 @@ namespace Barotrauma
private DateTime refreshDisableTimer; private DateTime refreshDisableTimer;
private bool waitingForRefresh; private bool waitingForRefresh;
private bool steamPingInfoReady;
private const float sidebarWidth = 0.2f; private const float sidebarWidth = 0.2f;
public ServerListScreen() public ServerListScreen()
{ {
@@ -1423,6 +1425,15 @@ namespace Barotrauma
{ {
if (waitingForRefresh) { return; } if (waitingForRefresh) { return; }
steamPingInfoReady = false;
CoroutineManager.StopCoroutines("EstimateLobbyPing");
TaskPool.Add(Steamworks.SteamNetworkingUtils.WaitForPingDataAsync(), (task) =>
{
steamPingInfoReady = true;
});
friendsListUpdateTime = Timing.TotalTime - 1.0; friendsListUpdateTime = Timing.TotalTime - 1.0;
UpdateFriendsList(); UpdateFriendsList();
@@ -1684,11 +1695,7 @@ namespace Barotrauma
} }
else if (serverInfo.PingLocation != null) else if (serverInfo.PingLocation != null)
{ {
Steamworks.Data.PingLocation pingLocation = serverInfo.PingLocation.Value; CoroutineManager.StartCoroutine(EstimateLobbyPing(serverInfo, serverPingText), "EstimateLobbyPing");
serverInfo.Ping = Steamworks.SteamNetworkingUtils.LocalPingLocation?.EstimatePingTo(pingLocation) ?? -1;
serverInfo.PingChecked = true;
serverPingText.TextColor = GetPingTextColor(serverInfo.Ping);
serverPingText.Text = serverInfo.Ping > -1 ? serverInfo.Ping.ToString() : "?";
} }
if (serverInfo.LobbyID == 0 && (string.IsNullOrWhiteSpace(serverInfo.IP) || string.IsNullOrWhiteSpace(serverInfo.Port))) if (serverInfo.LobbyID == 0 && (string.IsNullOrWhiteSpace(serverInfo.IP) || string.IsNullOrWhiteSpace(serverInfo.Port)))
@@ -1749,6 +1756,22 @@ namespace Barotrauma
FilterServers(); FilterServers();
} }
private IEnumerable<object> 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() private void ServerQueryFinished()
{ {
if (!serverList.Content.Children.Any()) if (!serverList.Content.Children.Any())
@@ -1435,7 +1435,7 @@ namespace Barotrauma
#if DEBUG #if DEBUG
deleteBtn.Enabled = true; deleteBtn.Enabled = true;
#else #else
deleteBtn.Enabled = userData is Submarine sub && sub.IsVanillaSubmarine(); deleteBtn.Enabled = userData is Submarine sub && !sub.IsVanillaSubmarine();
#endif #endif
} }
return true; return true;
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product> <Product>Barotrauma</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName> <AssemblyName>Barotrauma</AssemblyName>
+1 -1
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product> <Product>Barotrauma</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName> <AssemblyName>Barotrauma</AssemblyName>
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product> <Product>Barotrauma</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName> <AssemblyName>Barotrauma</AssemblyName>
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product> <Product>Barotrauma Dedicated Server</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName> <AssemblyName>DedicatedServer</AssemblyName>
+1 -1
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product> <Product>Barotrauma Dedicated Server</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName> <AssemblyName>DedicatedServer</AssemblyName>
@@ -313,11 +313,11 @@ namespace Barotrauma.Networking
List<NetEntityEvent> eventsToSync = null; List<NetEntityEvent> eventsToSync = null;
if (client.NeedsMidRoundSync) if (client.NeedsMidRoundSync)
{ {
eventsToSync = GetEventsToSync(client, uniqueEvents); eventsToSync = GetEventsToSync(client);
} }
else else
{ {
eventsToSync = GetEventsToSync(client, events); eventsToSync = GetEventsToSync(client);
} }
if (eventsToSync.Count == 0) if (eventsToSync.Count == 0)
@@ -380,13 +380,13 @@ namespace Barotrauma.Networking
/// <summary> /// <summary>
/// Returns a list of events that should be sent to the client from the eventList /// Returns a list of events that should be sent to the client from the eventList
/// </summary> /// </summary>
/// <param name="client"></param> private List<NetEntityEvent> GetEventsToSync(Client client)
/// <param name="eventList"></param>
/// <returns></returns>
private List<NetEntityEvent> GetEventsToSync(Client client, List<ServerEntityEvent> eventList)
{ {
List<NetEntityEvent> eventsToSync = new List<NetEntityEvent>(); List<NetEntityEvent> eventsToSync = new List<NetEntityEvent>();
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 //find the index of the first event the client hasn't received
int startIndex = eventList.Count; int startIndex = eventList.Count;
@@ -409,7 +409,18 @@ namespace Barotrauma.Networking
continue; 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; break;
} }
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace> <RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors> <Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product> <Product>Barotrauma Dedicated Server</Product>
<Version>0.9.700.0</Version> <Version>0.9.701.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright> <Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName> <AssemblyName>DedicatedServer</AssemblyName>
@@ -980,8 +980,7 @@ namespace Barotrauma
public void GiveJobItems(WayPoint spawnPoint = null) 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); info.Job.GiveJobItems(this, spawnPoint);
} }
@@ -420,7 +420,7 @@ namespace Barotrauma
if (logging) if (logging)
{ {
var fileMd5 = new Md5Hash(hash); var fileMd5 = new Md5Hash(hash);
DebugConsole.NewMessage(" " + file.Path + ": " + fileMd5.ShortHash); DebugConsole.NewMessage(" " + file.Path + ": " + fileMd5.Hash);
} }
hashes.Add(hash); hashes.Add(hash);
} }
@@ -440,7 +440,7 @@ namespace Barotrauma
md5Hash = new Md5Hash(bytes); md5Hash = new Md5Hash(bytes);
if (logging) if (logging)
{ {
DebugConsole.NewMessage("****************************** Package hash: " + md5Hash.ShortHash); DebugConsole.NewMessage("****************************** Package hash: " + md5Hash.Hash);
} }
} }
@@ -470,6 +470,14 @@ namespace Barotrauma
break; 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) foreach (string filePath in filePaths)
{ {
if (!File.Exists(filePath)) continue; if (!File.Exists(filePath)) continue;
@@ -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) => commands.Add(new Command("findentityids", "findentityids [entityname]", (string[] args) =>
{ {
if (args.Length == 0) return; 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("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) => 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; var variant = job != null ? Rand.Range(0, job.Variants, Rand.RandSync.Server) : 0;
CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, variant: variant); CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, variant: variant);
spawnedCharacter = Character.Create(characterInfo, spawnPosition, ToolBox.RandomSeed(8)); spawnedCharacter = Character.Create(characterInfo, spawnPosition, ToolBox.RandomSeed(8));
if (job != null) spawnedCharacter.GiveJobItems(spawnPoint);
{
spawnedCharacter.GiveJobItems(spawnPoint);
}
if (GameMain.GameSession != null) if (GameMain.GameSession != null)
{ {
@@ -10,6 +10,8 @@ namespace Barotrauma
{ {
private static readonly List<Item> spawnedItems = new List<Item>(); private static readonly List<Item> spawnedItems = new List<Item>();
public static bool OutputDebugInfo = false;
public static void PlaceIfNeeded(GameMode gameMode) public static void PlaceIfNeeded(GameMode gameMode)
{ {
if (GameMain.NetworkMember != null && !GameMain.NetworkMember.IsServer) { return; } if (GameMain.NetworkMember != null && !GameMain.NetworkMember.IsServer) { return; }
@@ -82,14 +84,24 @@ namespace Barotrauma
// Spawn items that don't have containers last // Spawn items that don't have containers last
prefabsWithoutContainer.Randomize().ForEach(i => SpawnItems(i)); prefabsWithoutContainer.Randomize().ForEach(i => SpawnItems(i));
DebugConsole.NewMessage("Automatically placed items: "); if (OutputDebugInfo)
foreach (string itemName in spawnedItems.Select(it => it.Name).Distinct())
{ {
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) 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; bool success = false;
foreach (PreferredContainer preferredContainer in itemPrefab.PreferredContainers) foreach (PreferredContainer preferredContainer in itemPrefab.PreferredContainers)
{ {
@@ -907,6 +907,7 @@ namespace Barotrauma
new XAttribute("width", GraphicsWidth), new XAttribute("width", GraphicsWidth),
new XAttribute("height", GraphicsHeight), new XAttribute("height", GraphicsHeight),
new XAttribute("vsync", VSyncEnabled), new XAttribute("vsync", VSyncEnabled),
new XAttribute("framelimit", Timing.FrameLimit),
new XAttribute("displaymode", windowMode)); new XAttribute("displaymode", windowMode));
} }
@@ -1228,6 +1229,7 @@ namespace Barotrauma
new XAttribute("width", GraphicsWidth), new XAttribute("width", GraphicsWidth),
new XAttribute("height", GraphicsHeight), new XAttribute("height", GraphicsHeight),
new XAttribute("vsync", VSyncEnabled), new XAttribute("vsync", VSyncEnabled),
new XAttribute("framelimit", Timing.FrameLimit),
new XAttribute("displaymode", windowMode)); new XAttribute("displaymode", windowMode));
} }
@@ -1423,6 +1425,7 @@ namespace Barotrauma
GraphicsWidth = graphicsMode.GetAttributeInt("width", GraphicsWidth); GraphicsWidth = graphicsMode.GetAttributeInt("width", GraphicsWidth);
GraphicsHeight = graphicsMode.GetAttributeInt("height", GraphicsHeight); GraphicsHeight = graphicsMode.GetAttributeInt("height", GraphicsHeight);
VSyncEnabled = graphicsMode.GetAttributeBool("vsync", VSyncEnabled); VSyncEnabled = graphicsMode.GetAttributeBool("vsync", VSyncEnabled);
Timing.FrameLimit = graphicsMode.GetAttributeInt("framelimit", 200);
XElement graphicsSettings = doc.Root.Element("graphicssettings"); XElement graphicsSettings = doc.Root.Element("graphicssettings");
ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", ParticleLimit); ParticleLimit = graphicsSettings.GetAttributeInt("particlelimit", ParticleLimit);
@@ -1504,6 +1507,7 @@ namespace Barotrauma
GraphicsWidth = 0; GraphicsWidth = 0;
GraphicsHeight = 0; GraphicsHeight = 0;
VSyncEnabled = true; VSyncEnabled = true;
Timing.FrameLimit = 200;
#if DEBUG #if DEBUG
EnableSplashScreen = false; EnableSplashScreen = false;
#else #else
@@ -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++) for (int i = 0; i < updateableComponents.Count; i++)
{ {
@@ -1306,7 +1306,7 @@ namespace Barotrauma
#endif #endif
ic.WasUsed = false; 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) if (ic.IsActive)
{ {
@@ -228,7 +228,9 @@ namespace Barotrauma
if (hulls[i] == null) hulls[i] = Hull.FindHullOld(searchPos[i], null, false, true); 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) if (hulls[0] == null && hulls[1] != null)
{ {
@@ -619,7 +619,10 @@ namespace Barotrauma
if (Bodies != null) if (Bodies != null)
{ {
foreach (Body b in Bodies) foreach (Body b in Bodies)
{
GameMain.World.Remove(b); GameMain.World.Remove(b);
}
Bodies.Clear();
} }
if (Sections != null) if (Sections != null)
@@ -648,7 +651,10 @@ namespace Barotrauma
if (Bodies != null) if (Bodies != null)
{ {
foreach (Body b in Bodies) foreach (Body b in Bodies)
{
GameMain.World.Remove(b); GameMain.World.Remove(b);
}
Bodies.Clear();
} }
if (Sections != null) if (Sections != null)
@@ -14,6 +14,7 @@ namespace Barotrauma.Networking
private static Stream writeStream; private static Stream writeStream;
private static Stream readStream; private static Stream readStream;
private static volatile bool shutDown; private static volatile bool shutDown;
private static ManualResetEvent writeManualResetEvent;
private static byte[] tempBytes; private static byte[] tempBytes;
private enum ReadState private enum ReadState
@@ -49,6 +50,8 @@ namespace Barotrauma.Networking
readCancellationToken = new CancellationTokenSource(); readCancellationToken = new CancellationTokenSource();
writeManualResetEvent = new ManualResetEvent(false);
readThread = new Thread(UpdateRead); readThread = new Thread(UpdateRead);
writeThread = new Thread(UpdateWrite); writeThread = new Thread(UpdateWrite);
readThread.Start(); readThread.Start();
@@ -58,6 +61,7 @@ namespace Barotrauma.Networking
private static void PrivateShutDown() private static void PrivateShutDown()
{ {
shutDown = true; shutDown = true;
writeManualResetEvent.Set();
readCancellationToken?.Cancel(); readCancellationToken?.Cancel();
readThread?.Join(); readThread = null; readThread?.Join(); readThread = null;
writeThread?.Join(); writeThread = null; writeThread?.Join(); writeThread = null;
@@ -152,7 +156,11 @@ namespace Barotrauma.Networking
msgAvailable = msgsToWrite.TryDequeue(out msg); msgAvailable = msgsToWrite.TryDequeue(out msg);
} }
} }
Thread.Yield(); if (!shutDown)
{
writeManualResetEvent.Reset();
writeManualResetEvent.WaitOne();
}
} }
} }
@@ -163,6 +171,7 @@ namespace Barotrauma.Networking
lock (msgsToWrite) lock (msgsToWrite)
{ {
msgsToWrite.Enqueue(msg); msgsToWrite.Enqueue(msg);
writeManualResetEvent.Set();
} }
} }
@@ -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); 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 try
{ {
@@ -20,10 +20,12 @@
public virtual void Select() public virtual void Select()
{ {
if (selected != null && selected != this) if (selected != null && selected != this)
{ {
selected.Deselect(); selected.Deselect();
#if CLIENT #if CLIENT
GUI.ClearCursorWait();
//make sure any textbox in the previously selected screen doesn't stay selected //make sure any textbox in the previously selected screen doesn't stay selected
if (GUI.KeyboardDispatcher.Subscriber != DebugConsole.TextBox) if (GUI.KeyboardDispatcher.Subscriber != DebugConsole.TextBox)
{ {
@@ -10,7 +10,28 @@ namespace Barotrauma
public static double TotalTime; public static double TotalTime;
public static double Accumulator; 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;
/// <summary>
/// Maximum FPS (0 = unlimited).
/// </summary>
public static int FrameLimit
{
get { return frameLimit; }
set
{
if (value <= 0)
{
frameLimit = 0;
}
else
{
frameLimit = Math.Max(value, FixedUpdateRate);
}
}
}
public static double Alpha public static double Alpha
{ {
Binary file not shown.
Binary file not shown.
Binary file not shown.
+25 -3
View File
@@ -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! - 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: 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). - 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. - 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. - 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. - 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. - 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. - 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. - 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. - 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. - 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. - 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 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. - Added muzzle flashes to small firearms.
@@ -82,8 +82,8 @@ namespace FarseerPhysics.Dynamics
BodyType = BodyType.Static; BodyType = BodyType.Static;
} }
public World World { get {return _world; } } public World World { get { return _world; } }
public int IslandIndex { get; set; } public int IslandIndex { get; set; }
/// <summary> /// <summary>
@@ -350,7 +350,17 @@ namespace FarseerPhysics.Dynamics
/// Create all proxies. /// Create all proxies.
/// </summary> /// </summary>
internal void CreateProxies() 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; IBroadPhase broadPhase = World.ContactManager.BroadPhase;
for (int i = 0; i < FixtureList.Count; i++) for (int i = 0; i < FixtureList.Count; i++)
FixtureList[i].CreateProxies(broadPhase, ref _xf); FixtureList[i].CreateProxies(broadPhase, ref _xf);
@@ -307,7 +307,7 @@ namespace FarseerPhysics.Dynamics
internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf) internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf)
{ {
if (ProxyCount != 0) 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. // Create proxies in the broad-phase.
ProxyCount = Shape.ChildCount; ProxyCount = Shape.ChildCount;