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;
}
}
}
}