using Barotrauma.Networking; using System; using System.Collections.Generic; using System.Linq; namespace Barotrauma.Items.Components; /// /// Base class for signal components that can select between input/output connections (e.g. multiplexer and demultiplexer components) /// abstract partial class ConnectionSelectorComponent : ItemComponent, IServerSerializable { protected int selectedConnectionIndex; protected string selectedConnectionIndexStr; protected string selectedConnectionName; private int connectionCount = -1; [InGameEditable, Serialize(0, IsPropertySaveable.Yes, description: "The index of the selected connection.", alwaysUseInstanceValues: true)] public int SelectedConnection { get { return selectedConnectionIndex; } set { int prevIndex = selectedConnectionIndex; // store original, so we know if the state has changed and can sync it in MP selectedConnectionIndex = Math.Max(0, value); //don't clamp until we've determined how many connections the item has //(can't be done until the connection panel component has been loaded too) if (connectionCount > -1) { selectedConnectionIndex = Math.Min(selectedConnectionIndex, connectionCount - 1); } selectedConnectionName = GetConnectionName(selectedConnectionIndex); selectedConnectionIndexStr = selectedConnectionIndex.ToString(); if (prevIndex != selectedConnectionIndex) { OnStateChanged(); } } } [InGameEditable, Serialize(true, IsPropertySaveable.Yes, description: "Should the selected connection go back to the first one when moving past the last one?", alwaysUseInstanceValues: true)] public bool WrapAround { get; set; } [InGameEditable, Serialize(true, IsPropertySaveable.Yes, description: "Should empty connections (connections with no wires in them) be skipped over when moving the selection?", alwaysUseInstanceValues: true)] public bool SkipEmptyConnections { get; set; } public ConnectionSelectorComponent(Item item, ContentXElement element) : base(item, element) { } partial void OnStateChanged(); protected abstract string GetConnectionName(int connectionIndex); /// /// Name of the input connection that sets the selected connection. /// protected abstract string InputNameSetConnection { get; } /// /// Name of the input connection that moves the selected connection. /// protected abstract string InputNameMoveInput { get; } protected abstract IEnumerable GetConnections(); public override void OnItemLoaded() { connectionCount = GetConnections().Count(); } public override void ReceiveSignal(Signal signal, Connection connection) { if (connection.Name == InputNameSetConnection) { if (int.TryParse(signal.value, out int newInput)) { SelectedConnection = newInput; } } else if (connection.Name == InputNameMoveInput) { if (int.TryParse(signal.value, out int moveAmount)) { if (SkipEmptyConnections) { for (int i = 0; i < connectionCount; i++) { moveInput(moveAmount); if (item.Connections.Any(c => c.Name == selectedConnectionName && (c.Wires.Any() || c.CircuitBoxConnections.Any()))) { break; } } } else { moveInput(moveAmount); } } } void moveInput(int moveAmount) { if (WrapAround) { SelectedConnection = MathUtils.PositiveModulo(selectedConnectionIndex + moveAmount, connectionCount); } else { SelectedConnection += moveAmount; } } } }