Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -3,7 +3,6 @@ using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -16,7 +15,7 @@ namespace Barotrauma.Items.Components
partial void InitProjSpecific(ContentXElement element)
{
terminalButtonStyles = new string[RequiredSignalCount];
terminalButtonStyles = new string[requiredSignalCount];
int i = 0;
foreach (var childElement in element.GetChildElements("TerminalButton"))
{
@@ -38,11 +37,11 @@ namespace Barotrauma.Items.Components
};
paddedFrame.OnAddedToGUIUpdateList += (component) =>
{
bool buttonsEnabled = AllowUsingButtons;
foreach (var child in component.Children)
bool buttonsEnabled = IsActivated;
foreach (GUIComponent child in component.Children)
{
if (!(child is GUIButton)) { continue; }
if (!(child.UserData is int)) { continue; }
if (child is not GUIButton) { continue; }
if (child.UserData is not int) { continue; }
child.Enabled = buttonsEnabled;
child.Children.ForEach(c => c.Enabled = buttonsEnabled);
}
@@ -59,7 +58,7 @@ namespace Barotrauma.Items.Components
containerIndicator.OverrideState = itemsContained ? GUIComponent.ComponentState.Selected : GUIComponent.ComponentState.None;
};
float x = 1.0f / (1 + RequiredSignalCount);
float x = 1.0f / (1 + requiredSignalCount);
float y = Math.Min((x * paddedFrame.Rect.Width) / paddedFrame.Rect.Height, 0.5f);
Vector2 relativeSize = new Vector2(x, y);
@@ -69,7 +68,7 @@ namespace Barotrauma.Items.Components
containerIndicator = new GUIImage(new RectTransform(new Vector2(0.5f, 0.5f * (1.0f - y)), containerSection.RectTransform, anchor: Anchor.BottomCenter),
style: "IndicatorLightRed", scaleToFit: true);
for (int i = 0; i < RequiredSignalCount; i++)
for (int i = 0; i < requiredSignalCount; i++)
{
var button = new GUIButton(new RectTransform(relativeSize, paddedFrame.RectTransform), style: null)
{
@@ -111,7 +110,7 @@ namespace Barotrauma.Items.Components
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), sender: null, isServerMessage: true);
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), sender: null, ignoreState: true);
}
}
}
@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System;
using System.Collections.Generic;
@@ -129,7 +129,7 @@ namespace Barotrauma.Items.Components
public void RemoveComponents(IReadOnlyCollection<CircuitBoxComponent> node)
{
if (Locked) { return; }
if (IsLocked()) { return; }
var ids = node.Select(static n => n.ID).ToImmutableArray();
if (GameMain.NetworkMember is null)
@@ -146,7 +146,7 @@ namespace Barotrauma.Items.Components
public void AddWire(CircuitBoxConnection one, CircuitBoxConnection two)
{
if (Locked) { return; }
if (IsLocked()) { return; }
if (GameMain.NetworkMember is null)
{
Connect(one, two, static delegate { }, CircuitBoxWire.SelectedWirePrefab);
@@ -160,7 +160,7 @@ namespace Barotrauma.Items.Components
public void RemoveWires(IReadOnlyCollection<CircuitBoxWire> wires)
{
if (Locked) { return; }
if (IsLocked()) { return; }
var ids = wires.Select(static w => w.ID).ToImmutableArray();
if (GameMain.NetworkMember is null)
{
@@ -230,7 +230,7 @@ namespace Barotrauma.Items.Components
public void MoveComponent(Vector2 moveAmount, IReadOnlyCollection<CircuitBoxNode> moveables)
{
if (Locked) { return; }
if (IsLocked()) { return; }
var ids = ImmutableArray.CreateBuilder<ushort>();
var ios = ImmutableArray.CreateBuilder<CircuitBoxInputOutputNode.Type>();
var labelIds = ImmutableArray.CreateBuilder<ushort>();
@@ -265,7 +265,7 @@ namespace Barotrauma.Items.Components
public void AddComponent(ItemPrefab prefab, Vector2 pos)
{
if (Locked) { return; }
if (IsLocked()) { return; }
if (GameMain.NetworkMember is null)
{
ItemPrefab resource;
@@ -292,7 +292,7 @@ namespace Barotrauma.Items.Components
public void RenameLabel(CircuitBoxLabelNode label, Color color, NetLimitedString header, NetLimitedString body)
{
if (Locked) { return; }
if (IsLocked()) { return; }
if (GameMain.NetworkMember is null)
{
label.EditText(header, body);
@@ -316,7 +316,7 @@ namespace Barotrauma.Items.Components
public void ResizeNode(CircuitBoxNode node, CircuitBoxResizeDirection dir, Vector2 amount)
{
if (Locked) { return; }
if (IsLocked()) { return; }
var resize = node.ResizeBy(dir, amount);
if (GameMain.NetworkMember is null)
{
@@ -341,7 +341,7 @@ namespace Barotrauma.Items.Components
public void AddLabel(Vector2 pos)
{
if (Locked) { return; }
if (IsLocked()) { return; }
if (GameMain.NetworkMember is null)
{
AddLabelInternal(ICircuitBoxIdentifiable.FindFreeID(Labels), GUIStyle.Blue, pos, CircuitBoxLabelNode.DefaultHeaderText, NetLimitedString.Empty);
@@ -353,7 +353,7 @@ namespace Barotrauma.Items.Components
public void RemoveLabel(IReadOnlyCollection<CircuitBoxLabelNode> labels)
{
if (Locked) { return; }
if (IsLocked()) { return; }
if (!labels.Any()) { return; }
var ids = labels.Select(static n => n.ID).ToImmutableArray();
@@ -12,7 +12,9 @@ namespace Barotrauma.Items.Components
private readonly List<GUIComponent> uiElements = new List<GUIComponent>();
private GUILayoutGroup uiElementContainer;
private bool readingNetworkEvent;
private bool suppressNetworkEvents;
private GUIComponent insufficientPowerWarning;
private Point ElementMaxSize => new Point(uiElementContainer.Rect.Width, (int)(65 * GUI.yScale));
@@ -40,7 +42,7 @@ namespace Barotrauma.Items.Components
float elementSize = Math.Min(1.0f / visibleElements.Count(), 1);
foreach (CustomInterfaceElement ciElement in visibleElements)
{
if (ciElement.HasPropertyName)
if (ciElement.InputType is CustomInterfaceElement.InputTypeOption.Number or CustomInterfaceElement.InputTypeOption.Text)
{
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal: true)
{
@@ -49,7 +51,7 @@ namespace Barotrauma.Items.Components
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
TextManager.Get(ciElement.Label).Fallback(ciElement.Label));
if (!ciElement.IsNumberInput)
if (ciElement.InputType is CustomInterfaceElement.InputTypeOption.Text)
{
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), ciElement.Signal, style: "GUITextBoxNoIcon")
{
@@ -68,7 +70,7 @@ namespace Barotrauma.Items.Components
}
else
{
item.CreateClientEvent(this);
CreateClientEventWithCorrectionDelay();
}
};
@@ -98,13 +100,10 @@ namespace Barotrauma.Items.Components
ValueStep = numberInputStep,
OnValueChanged = (ni) =>
{
if (GameMain.Client == null)
ValueChanged(ni.UserData as CustomInterfaceElement, ni.FloatValue);
if (!suppressNetworkEvents && GameMain.Client != null)
{
ValueChanged(ni.UserData as CustomInterfaceElement, ni.FloatValue);
}
else if (!readingNetworkEvent)
{
item.CreateClientEvent(this);
CreateClientEventWithCorrectionDelay();
}
}
};
@@ -124,13 +123,10 @@ namespace Barotrauma.Items.Components
ValueStep = numberInputStep,
OnValueChanged = (ni) =>
{
if (GameMain.Client == null)
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
if (!suppressNetworkEvents && GameMain.Client != null)
{
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
}
else if (!readingNetworkEvent)
{
item.CreateClientEvent(this);
CreateClientEventWithCorrectionDelay();
}
}
};
@@ -149,7 +145,7 @@ namespace Barotrauma.Items.Components
}
}
}
else if (ciElement.ContinuousSignal)
else if (ciElement.InputType is CustomInterfaceElement.InputTypeOption.TickBox)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform)
{
@@ -160,13 +156,10 @@ namespace Barotrauma.Items.Components
};
tickBox.OnSelected += (tBox) =>
{
if (GameMain.Client == null)
TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
if (!suppressNetworkEvents && GameMain.Client != null)
{
TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
}
else if (!readingNetworkEvent)
{
item.CreateClientEvent(this);
CreateClientEventWithCorrectionDelay();
}
return true;
};
@@ -175,7 +168,7 @@ namespace Barotrauma.Items.Components
tickBox.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
uiElements.Add(tickBox);
}
else
else if (ciElement.InputType is CustomInterfaceElement.InputTypeOption.Button)
{
var btn = new GUIButton(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform),
TextManager.Get(ciElement.Label).Fallback(ciElement.Label), style: "DeviceButton")
@@ -189,8 +182,10 @@ namespace Barotrauma.Items.Components
{
ButtonClicked(btnElement);
}
else if (!readingNetworkEvent)
else if (!suppressNetworkEvents && GameMain.Client != null)
{
//don't use CreateClientEventWithCorrectionDelay here, because buttons have no state,
//which means we don't need to worry about server updates interfering with client-side changes to the values in the interface
item.CreateClientEvent(this, new EventData(btnElement));
}
return true;
@@ -203,6 +198,22 @@ namespace Barotrauma.Items.Components
uiElements.Add(btn);
}
}
if (ShowInsufficientPowerWarning)
{
insufficientPowerWarning = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), GuiFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { MinSize = new Point(0, GUI.IntScale(30)) },
TextManager.Get("SteeringNoPowerTip"), font: GUIStyle.Font, wrap: true, style: "GUIToolTip", textAlignment: Alignment.Center)
{
AutoScaleHorizontal = true,
Visible = false
};
}
void CreateClientEventWithCorrectionDelay()
{
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
}
public override void CreateEditingHUD(SerializableEntityEditor editor)
@@ -253,7 +264,20 @@ namespace Barotrauma.Items.Components
{
if (uiElement.UserData is not CustomInterfaceElement element) { continue; }
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Count > 0);
if (visible) { visibleElementCount++; }
if (visible)
{
visibleElementCount++;
if (element.GetValueInterval > 0.0f && correctionTimer <= 0.0f)
{
element.GetValueTimer -= deltaTime;
if (element.GetValueTimer <= 0.0f)
{
SetSignalToPropertyValue(element);
UpdateSignalProjSpecific(uiElement);
element.GetValueTimer = element.GetValueInterval;
}
}
}
if (uiElement.Visible != visible)
{
uiElement.Visible = visible;
@@ -274,6 +298,11 @@ namespace Barotrauma.Items.Components
GuiFrame.Visible = visibleElementCount > 0;
uiElementContainer.Recalculate();
}
if (insufficientPowerWarning != null)
{
insufficientPowerWarning.Visible = item.GetComponents<Powered>().Any(p => p.PowerConsumption > 0.0f && p.Voltage < p.MinVoltage);
}
}
partial void UpdateLabelsProjSpecific()
@@ -300,7 +329,7 @@ namespace Barotrauma.Items.Components
LocalizedString CreateLabelText(int elementIndex)
{
var label = customInterfaceElementList[elementIndex].Label;
string label = customInterfaceElementList[elementIndex].Label;
return string.IsNullOrWhiteSpace(label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (elementIndex + 1).ToString()) :
TextManager.Get(label).Fallback(label);
@@ -336,22 +365,43 @@ namespace Barotrauma.Items.Components
if (signals == null) { return; }
for (int i = 0; i < signals.Length && i < uiElements.Count; i++)
{
string signal = customInterfaceElementList[i].Signal;
if (uiElements[i] is GUITextBox tb)
UpdateSignalProjSpecific(uiElements[i]);
}
}
private void UpdateSignalProjSpecific(GUIComponent uiElement)
{
if (uiElement.UserData is not CustomInterfaceElement element) { return; }
suppressNetworkEvents = true;
string signal = element.Signal;
if (uiElement is GUITextBox tb)
{
tb.Text = Screen.Selected is { IsEditor: true } ?
signal :
TextManager.Get(signal).Fallback(signal).Value;
}
else if (uiElement is GUINumberInput ni)
{
if (ni.InputType == NumberType.Int)
{
tb.Text = Screen.Selected is { IsEditor: true } ?
signal :
TextManager.Get(signal).Fallback(signal).Value;
}
else if (uiElements[i] is GUINumberInput ni)
{
if (ni.InputType == NumberType.Int)
if (int.TryParse(signal, out int value))
{
int.TryParse(signal, out int value);
ni.IntValue = value;
}
else if (float.TryParse(signal, out float floatValue))
{
ni.IntValue = (int)MathF.Round(floatValue);
}
}
}
else if (uiElement is GUITickBox tickBox)
{
tickBox.Selected = signal.Equals("true", StringComparison.OrdinalIgnoreCase);
}
suppressNetworkEvents = false;
}
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
@@ -360,14 +410,9 @@ namespace Barotrauma.Items.Components
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
var element = customInterfaceElementList[i];
if (element.HasPropertyName)
switch (element.InputType)
{
if (!element.IsNumberInput)
{
msg.WriteString(((GUITextBox)uiElements[i]).Text);
}
else
{
case CustomInterfaceElement.InputTypeOption.Number:
switch (element.NumberType)
{
case NumberType.Float:
@@ -378,59 +423,82 @@ namespace Barotrauma.Items.Components
msg.WriteString(((GUINumberInput)uiElements[i]).IntValue.ToString());
break;
}
}
}
else if (element.ContinuousSignal)
{
msg.WriteBoolean(((GUITickBox)uiElements[i]).Selected);
}
else
{
msg.WriteBoolean(extraData is Item.ComponentStateEventData { ComponentData: EventData eventData } && eventData.BtnElement == customInterfaceElementList[i]);
break;
case CustomInterfaceElement.InputTypeOption.Text:
msg.WriteString(((GUITextBox)uiElements[i]).Text);
break;
case CustomInterfaceElement.InputTypeOption.TickBox:
msg.WriteBoolean(((GUITickBox)uiElements[i]).Selected);
break;
case CustomInterfaceElement.InputTypeOption.Button:
msg.WriteBoolean(extraData is Item.ComponentStateEventData { ComponentData: EventData eventData } && eventData.BtnElement == customInterfaceElementList[i]);
break;
}
}
}
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
readingNetworkEvent = true;
int msgStartPos = msg.BitPosition;
suppressNetworkEvents = true;
try
{
string[] stringValues = new string[customInterfaceElementList.Count];
bool[] boolValues = new bool[customInterfaceElementList.Count];
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
var element = customInterfaceElementList[i];
if (element.HasPropertyName)
switch (element.InputType)
{
string newValue = msg.ReadString();
if (!element.IsNumberInput)
{
TextChanged(element, newValue);
}
else
{
case CustomInterfaceElement.InputTypeOption.Number:
case CustomInterfaceElement.InputTypeOption.Text:
stringValues[i] = msg.ReadString();
break;
case CustomInterfaceElement.InputTypeOption.TickBox:
case CustomInterfaceElement.InputTypeOption.Button:
boolValues[i] = msg.ReadBoolean();
break;
}
}
if (correctionTimer > 0.0f)
{
int msgLength = msg.BitPosition - msgStartPos;
msg.BitPosition = msgStartPos;
StartDelayedCorrection(msg.ExtractBits(msgLength), sendingTime);
return;
}
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
var element = customInterfaceElementList[i];
switch (element.InputType)
{
case CustomInterfaceElement.InputTypeOption.Number:
switch (element.NumberType)
{
case NumberType.Int when int.TryParse(newValue, out int value):
case NumberType.Int when int.TryParse(stringValues[i], out int value):
ValueChanged(element, value);
break;
case NumberType.Float when TryParseFloatInvariantCulture(newValue, out float value):
case NumberType.Float when TryParseFloatInvariantCulture(stringValues[i], out float value):
ValueChanged(element, value);
break;
}
}
}
else
{
bool elementState = msg.ReadBoolean();
if (element.ContinuousSignal)
{
((GUITickBox)uiElements[i]).Selected = elementState;
TickBoxToggled(element, elementState);
}
else if (elementState)
{
ButtonClicked(element);
}
break;
case CustomInterfaceElement.InputTypeOption.Text:
TextChanged(element, stringValues[i]);
break;
case CustomInterfaceElement.InputTypeOption.TickBox:
bool tickBoxState = boolValues[i];
((GUITickBox)uiElements[i]).Selected = tickBoxState;
TickBoxToggled(element, tickBoxState);
break;
case CustomInterfaceElement.InputTypeOption.Button:
if (boolValues[i])
{
ButtonClicked(element);
}
break;
}
}
@@ -438,7 +506,7 @@ namespace Barotrauma.Items.Components
}
finally
{
readingNetworkEvent = false;
suppressNetworkEvents = false;
}
}
}
@@ -1,6 +1,7 @@
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
@@ -21,13 +22,16 @@ namespace Barotrauma.Items.Components
private GUIListBox historyBox;
private GUITextBlock fillerBlock;
private GUITextBox inputBox;
private GUILayoutGroup layoutGroup;
private bool shouldSelectInputBox;
private readonly List<GUIComponent> inputElements = new List<GUIComponent>();
partial void InitProjSpecific(XElement element)
{
float marginMultiplier = element.GetAttributeFloat("marginmultiplier", 1.0f);
var layoutGroup = new GUILayoutGroup(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin.Multiply(marginMultiplier), GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset.Multiply(marginMultiplier) })
layoutGroup = new GUILayoutGroup(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin.Multiply(marginMultiplier), GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset.Multiply(marginMultiplier) })
{
ChildAnchor = Anchor.TopCenter,
RelativeSpacing = 0.02f,
@@ -39,43 +43,53 @@ namespace Barotrauma.Items.Components
AutoHideScrollBar = this.AutoHideScrollbar
};
if (!Readonly)
inputElements.Add(CreateFillerBlock());
inputElements.Add(new GUIFrame(new RectTransform(new Vector2(0.9f, 0.01f), layoutGroup.RectTransform), style: "HorizontalLine"));
inputBox = new GUITextBox(new RectTransform(new Vector2(1, .1f), layoutGroup.RectTransform), textColor: TextColor)
{
CreateFillerBlock();
new GUIFrame(new RectTransform(new Vector2(0.9f, 0.01f), layoutGroup.RectTransform), style: "HorizontalLine");
inputBox = new GUITextBox(new RectTransform(new Vector2(1, .1f), layoutGroup.RectTransform), textColor: TextColor)
MaxTextLength = MaxMessageLength,
OverflowClip = true,
OnEnterPressed = (GUITextBox textBox, string text) =>
{
MaxTextLength = MaxMessageLength,
OverflowClip = true,
OnEnterPressed = (GUITextBox textBox, string text) =>
if (GameMain.NetworkMember == null)
{
if (GameMain.NetworkMember == null)
{
SendOutput(text);
}
else
{
item.CreateClientEvent(this, new ClientEventData(text));
}
textBox.Text = string.Empty;
return true;
SendOutput(text);
}
};
}
else
{
item.CreateClientEvent(this, new ClientEventData(text));
}
textBox.Text = string.Empty;
return true;
}
};
inputElements.Add(inputBox);
RefreshInputElements();
}
layoutGroup.Recalculate();
/// <summary>
/// Refreshes the visibility of the input box and the layout of the UI depending on whether the terminal is readonly or not.
/// </summary>
private void RefreshInputElements()
{
foreach (var inputElement in inputElements)
{
inputElement.Visible = !_readonly;
inputElement.IgnoreLayoutGroups = !inputElement.Visible;
}
layoutGroup?.Recalculate();
}
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
// This could be removed if GUIListBox supported aligning its children
public void CreateFillerBlock()
public GUIComponent CreateFillerBlock()
{
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
{
CanBeFocused = false
};
return fillerBlock;
}
private void SendOutput(string input)
@@ -21,9 +21,14 @@ namespace Barotrauma.Items.Components
ShapeExtensions.DrawCircle(spriteBatch, pos, range, 32, Color.Cyan * 0.5f, 3);
}
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
{
SharedEventWrite(msg);
}
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
Channel = msg.ReadRangedInteger(MinChannel, MaxChannel);
SharedEventRead(msg);
}
}
}
@@ -106,13 +106,6 @@ namespace Barotrauma.Items.Components
private static int? selectedNodeIndex;
private static int? highlightedNodeIndex;
[Serialize(0.3f, IsPropertySaveable.No)]
public float Width
{
get;
set;
}
public Vector2 DrawSize
{
get { return sectionExtents; }
@@ -199,6 +192,8 @@ namespace Barotrauma.Items.Components
return;
}
if (Width * wireSprite.size.Y * Screen.Selected.Cam.Zoom < 1.0f) { return; }
Vector2 drawOffset = GetDrawOffset() + offset;
float baseDepth = UseSpriteDepth ? item.SpriteDepth : wireSprite.Depth;