diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs index 93b37d1f6..7efc9cf88 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs @@ -182,8 +182,8 @@ namespace Barotrauma.Items.Components GameServer.Log(Character.Controlled.LogName + " connected a wire from " + Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction); } - - Wires[index] = draggingConnected; + + AddLink(index, draggingConnected); } } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerTransfer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerTransfer.cs index 575b0b4c8..4e0680e11 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerTransfer.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Power/PowerTransfer.cs @@ -9,9 +9,7 @@ namespace Barotrauma.Items.Components { static float fullPower; static float fullLoad; - - //private bool updated; - + private int updateTimer; const float FireProbability = 0.15f; @@ -19,35 +17,82 @@ namespace Barotrauma.Items.Components //affects how fast changes in power/load are carried over the grid static float inertia = 5.0f; - static HashSet connectedList = new HashSet(); - + private HashSet connectedPoweredList = new HashSet(); private List powerConnections; + + private Dictionary connectionDirty = new Dictionary(); + + //a list of connections a given connection is connected to, either directly or via other power transfer components + private Dictionary> connectedRecipients = new Dictionary>(); private float powerLoad; + private bool isBroken; + public float PowerLoad { get { return powerLoad; } } //can the component transfer power - public virtual bool CanTransfer + private bool canTransfer; + public bool CanTransfer { - get { return IsActive; } + get { return canTransfer; } + set + { + if (canTransfer == value) return; + canTransfer = value; + SetAllConnectionsDirty(); + } + } + + public override bool IsActive + { + get + { + return base.IsActive; + } + + set + { + if (base.IsActive != value) SetAllConnectionsDirty(); + base.IsActive = value; + } } public PowerTransfer(Item item, XElement element) : base(item, element) { IsActive = true; + canTransfer = true; powerConnections = new List(); } + public override void UpdateBroken(float deltaTime, Camera cam) + { + base.UpdateBroken(deltaTime, cam); + + if (!isBroken) + { + SetAllConnectionsDirty(); + isBroken = true; + } + } + public override void Update(float deltaTime, Camera cam) { if (!CanTransfer) return; + if (isBroken) + { + SetAllConnectionsDirty(); + isBroken = false; + } + + RefreshConnections(); + if (updateTimer > 0) { //this junction box has already been updated this frame @@ -60,16 +105,13 @@ namespace Barotrauma.Items.Components fullPower = 0.0f; fullLoad = 0.0f; - connectedList.Clear(); + connectedPoweredList.Clear(); - CheckJunctions(deltaTime); + CheckPower(deltaTime); updateTimer = 0; - foreach (Powered p in connectedList) - { - PowerTransfer pt = p as PowerTransfer; - if (pt == null) continue; - + foreach (PowerTransfer pt in connectedPoweredList) + { pt.powerLoad += (fullLoad - pt.powerLoad) / inertia; pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia; pt.Item.SendSignal(0, "", "power", null, fullPower / Math.Max(fullLoad, 1.0f)); @@ -112,39 +154,99 @@ namespace Barotrauma.Items.Components return picker != null; } + private void RefreshConnections() + { + var connections = item.Connections; + foreach (Connection c in connections) + { + if (!connectionDirty[c]) continue; + + HashSet connected = new HashSet(); + if (!connectedRecipients.ContainsKey(c)) + { + connectedRecipients.Add(c, connected); + } + else + { + //mark all previous recipients as dirty + foreach (Connection recipient in connectedRecipients[c]) + { + var pt = recipient.Item.GetComponent(); + if (pt != null) pt.connectionDirty[recipient] = true; + } + } + + //find all connections that are connected to this one (directly or via another PowerTransfer) + connected.Add(c); + GetConnected(c, connected); + connectedRecipients[c] = connected; + + //go through all the PowerTransfers and we're connected to and set their connections to match the ones we just calculated + //(no need to go through the recursive GetConnected method again) + foreach (Connection recipient in connected) + { + var recipientPowerTransfer = recipient.Item.GetComponent(); + if (recipientPowerTransfer == null) continue; + + if (!connectedRecipients.ContainsKey(recipient)) + { + connectedRecipients.Add(recipient, connected); + } + + recipientPowerTransfer.connectedRecipients[recipient] = connected; + recipientPowerTransfer.connectionDirty[recipient] = false; + } + } + } + + //Finds all the connections that can receive a signal sent into the given connection and stores them in the hashset. + private void GetConnected(Connection c, HashSet connected) + { + var recipients = c.Recipients; + + foreach (Connection recipient in recipients) + { + if (recipient == null || connected.Contains(recipient)) continue; + + Item it = recipient.Item; + if (it == null || it.Condition <= 0.0f) continue; + + connected.Add(recipient); + + var powerTransfer = it.GetComponent(); + if (powerTransfer != null && powerTransfer.CanTransfer && powerTransfer.IsActive) + { + GetConnected(recipient, connected); + } + } + } + //a recursive function that goes through all the junctions and adds up //all the generated/consumed power of the constructions connected to the grid - private void CheckJunctions(float deltaTime) + private void CheckPower(float deltaTime) { updateTimer = 1; - connectedList.Add(this); - ApplyStatusEffects(ActionType.OnActive, deltaTime, null); - + connectedPoweredList.Clear(); + foreach (Connection c in powerConnections) { - var recipients = c.Recipients; - + HashSet recipients = connectedRecipients[c]; foreach (Connection recipient in recipients) { if (recipient == null) continue; Item it = recipient.Item; - if (it == null) continue; - - if (it.Condition <= 0.0f) continue; + if (it == null || it.Condition <= 0.0f) continue; foreach (Powered powered in it.GetComponents()) { if (powered == null || !powered.IsActive) continue; - - if (connectedList.Contains(powered)) continue; - PowerTransfer powerTransfer = powered as PowerTransfer; if (powerTransfer != null) { - if (!powerTransfer.CanTransfer) continue; - powerTransfer.CheckJunctions(deltaTime); + connectedPoweredList.Add(powerTransfer); + powerTransfer.updateTimer = 1; continue; } @@ -162,25 +264,38 @@ namespace Barotrauma.Items.Components } else { - connectedList.Add(powered); //positive power consumption = the construction requires power -> increase load if (powered.CurrPowerConsumption > 0.0f) { fullLoad += powered.CurrPowerConsumption; } else if (powered.CurrPowerConsumption < 0.0f) - //negative power consumption = the construction is a - //generator/battery or another junction box + //negative power consumption = the construction is a /generator/battery { fullPower -= powered.CurrPowerConsumption; } } } - } + } + } + + public void SetAllConnectionsDirty() + { + if (item.Connections == null) return; + foreach (Connection c in item.Connections) + { + connectionDirty[c] = true; } } - + + public void SetConnectionDirty(Connection connection) + { + var connections = item.Connections; + if (connections == null || !connections.Contains(connection)) return; + connectionDirty[connection] = true; + } + public override void OnMapLoaded() { var connections = item.Connections; @@ -189,18 +304,38 @@ namespace Barotrauma.Items.Components IsActive = false; return; } - + powerConnections = connections.FindAll(c => c.IsPower); if (powerConnections.Count == 0) IsActive = false; + + SetAllConnectionsDirty(); } public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power) { base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power); + if (!connectedRecipients.ContainsKey(connection)) return; + if (connection.Name.Length > 5 && connection.Name.Substring(0, 6).ToLowerInvariant() == "signal") { - connection.SendSignal(stepsTaken, signal, source, sender, 0.0f); + foreach (Connection recipient in connectedRecipients[connection]) + { + if (recipient.Item == item || recipient.Item == source) continue; + + foreach (ItemComponent ic in recipient.Item.components) + { + //powertransfer components don't need to receive the signal because we relay it straight + //to the connected items without going through the whole chain of junction boxes + if (ic is PowerTransfer) continue; + ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, 0.0f); + } + + foreach (StatusEffect effect in recipient.effects) + { + recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f); + } + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Connection.cs index 4beb77dca..de7641d6d 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Connection.cs @@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components private static Wire draggingConnected; - private List effects; + public readonly List effects; public readonly ushort[] wireId; @@ -167,8 +167,6 @@ namespace Barotrauma.Items.Components foreach (StatusEffect effect in recipient.effects) { - - //effect.Apply(ActionType.OnUse, 1.0f, recipient.item, recipient.item); recipient.item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f); } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/RelayComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/RelayComponent.cs index 594fb71b7..e236086cb 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/RelayComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/RelayComponent.cs @@ -31,21 +31,14 @@ namespace Barotrauma.Items.Components set { isOn = value; + CanTransfer = value; if (!isOn) { currPowerConsumption = 0.0f; } } } - - public override bool CanTransfer - { - get - { - return isOn; - } - } - + public RelayComponent(Item item, XElement element) : base (item, element) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs index f32fa02d9..cc44dd0b8 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs @@ -86,14 +86,15 @@ namespace Barotrauma.Items.Components public void RemoveConnection(Item item) { - for (int i = 0; i<2; i++) + for (int i = 0; i < 2; i++) { - if (connections[i]==null || connections[i].Item!=item) continue; - - for (int n = 0; n< connections[i].Wires.Length; n++) + if (connections[i] == null || connections[i].Item != item) continue; + + for (int n = 0; n < connections[i].Wires.Length; n++) { if (connections[i].Wires[n] != this) continue; + SetConnectedDirty(); connections[i].Wires[n] = null; } connections[i] = null; @@ -104,6 +105,8 @@ namespace Barotrauma.Items.Components { if (connection == connections[0]) connections[0] = null; if (connection == connections[1]) connections[1] = null; + + SetConnectedDirty(); } public bool Connect(Connection newConnection, bool addNode = true, bool sendNetworkEvent = false) @@ -137,8 +140,7 @@ namespace Barotrauma.Items.Components if (newConnection.Item.Submarine == null) continue; if (nodes.Count > 0 && nodes[0] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; - if (nodes.Count > 1 && nodes[nodes.Count-1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; - + if (nodes.Count > 1 && nodes[nodes.Count - 1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; if (i == 0) { @@ -148,11 +150,12 @@ namespace Barotrauma.Items.Components { nodes.Add(newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition); } - break; } + SetConnectedDirty(); + if (connections[0] != null && connections[1] != null) { foreach (ItemComponent ic in item.components) @@ -323,6 +326,8 @@ namespace Barotrauma.Items.Components connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction); } } + + SetConnectedDirty(); for (int i = 0; i < 2; i++) { @@ -363,6 +368,18 @@ namespace Barotrauma.Items.Components return position; } + public void SetConnectedDirty() + { + for (int i = 0; i < 2; i++) + { + if (connections[i]?.Item != null) + { + var pt = connections[i].Item.GetComponent(); + if (pt != null) pt.SetConnectionDirty(connections[i]); + } + } + } + private void CleanNodes() { for (int i = nodes.Count - 2; i > 0; i--)