committed by
GitHub
parent
ea60a81fdf
commit
103bc19508
@@ -8,6 +8,7 @@ using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -36,19 +37,23 @@ namespace Content.Server.AME
|
||||
|
||||
public int CoreCount => _cores.Count;
|
||||
|
||||
protected override void OnAddNode(Node node)
|
||||
public override void LoadNodes(List<Node> groupNodes)
|
||||
{
|
||||
base.OnAddNode(node);
|
||||
if (_masterController == null)
|
||||
base.LoadNodes(groupNodes);
|
||||
|
||||
foreach (var node in groupNodes)
|
||||
{
|
||||
node.Owner.TryGetComponent<AMEControllerComponent>(out var controller);
|
||||
_masterController = controller;
|
||||
if (node.Owner.TryGetComponent(out AMEControllerComponent? controller))
|
||||
{
|
||||
_masterController = controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRemoveNode(Node node)
|
||||
public override void RemoveNode(Node node)
|
||||
{
|
||||
base.OnRemoveNode(node);
|
||||
base.RemoveNode(node);
|
||||
|
||||
RefreshAMENodes(_masterController);
|
||||
if (_masterController != null && _masterController?.Owner == node.Owner) { _masterController = null; }
|
||||
}
|
||||
@@ -119,7 +124,7 @@ namespace Content.Server.AME
|
||||
// fuel > safeFuelLimit: Slow damage. Can safely run at this level for burst periods if the engine is small and someone is keeping an eye on it.
|
||||
if (_random.Prob(0.5f))
|
||||
instability = 1;
|
||||
// overloadVsSizeResult > 5:
|
||||
// overloadVsSizeResult > 5:
|
||||
if (overloadVsSizeResult > 5)
|
||||
instability = 5;
|
||||
// overloadVsSizeResult > 10: This will explode in at most 5 injections.
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Content.Server.AME.Components
|
||||
private AppearanceComponent? _appearance;
|
||||
private PowerSupplierComponent? _powerSupplier;
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
private int _stability = 100;
|
||||
@@ -92,7 +92,7 @@ namespace Content.Server.AME.Components
|
||||
if(fuelJar != null && _powerSupplier != null)
|
||||
{
|
||||
var availableInject = fuelJar.FuelAmount >= InjectionAmount ? InjectionAmount : fuelJar.FuelAmount;
|
||||
_powerSupplier.SupplyRate = group.InjectFuel(availableInject, out var overloading);
|
||||
_powerSupplier.MaxSupply = group.InjectFuel(availableInject, out var overloading);
|
||||
fuelJar.FuelAmount -= availableInject;
|
||||
InjectSound(overloading);
|
||||
UpdateUserInterface();
|
||||
@@ -252,7 +252,7 @@ namespace Content.Server.AME.Components
|
||||
_appearance?.SetData(AMEControllerVisuals.DisplayState, "off");
|
||||
if (_powerSupplier != null)
|
||||
{
|
||||
_powerSupplier.SupplyRate = 0;
|
||||
_powerSupplier.MaxSupply = 0;
|
||||
}
|
||||
}
|
||||
_injecting = !_injecting;
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.APC.Components;
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.Power.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.APC
|
||||
{
|
||||
public interface IApcNet
|
||||
{
|
||||
bool Powered { get; }
|
||||
|
||||
void AddApc(ApcComponent apc);
|
||||
|
||||
void RemoveApc(ApcComponent apc);
|
||||
|
||||
void AddPowerProvider(PowerProviderComponent provider);
|
||||
|
||||
void RemovePowerProvider(PowerProviderComponent provider);
|
||||
|
||||
void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad);
|
||||
|
||||
void Update(float frameTime);
|
||||
|
||||
GridId? GridId { get; }
|
||||
}
|
||||
|
||||
[NodeGroup(NodeGroupID.Apc)]
|
||||
public class ApcNetNodeGroup : BaseNetConnectorNodeGroup<BaseApcNetComponent, IApcNet>, IApcNet
|
||||
{
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<ApcComponent, BatteryComponent> _apcBatteries = new();
|
||||
|
||||
[ViewVariables]
|
||||
private readonly List<PowerProviderComponent> _providers = new();
|
||||
|
||||
[ViewVariables]
|
||||
public bool Powered { get => _powered; private set => SetPowered(value); }
|
||||
private bool _powered = false;
|
||||
|
||||
//Debug property
|
||||
[ViewVariables]
|
||||
private int TotalReceivers => _providers.SelectMany(provider => provider.LinkedReceivers).Count();
|
||||
|
||||
[ViewVariables]
|
||||
private int TotalPowerReceiverLoad { get => _totalPowerReceiverLoad; set => SetTotalPowerReceiverLoad(value); }
|
||||
|
||||
GridId? IApcNet.GridId => GridId;
|
||||
|
||||
private int _totalPowerReceiverLoad = 0;
|
||||
|
||||
public static readonly IApcNet NullNet = new NullApcNet();
|
||||
|
||||
public override void Initialize(Node sourceNode)
|
||||
{
|
||||
base.Initialize(sourceNode);
|
||||
|
||||
EntitySystem.Get<ApcNetSystem>().AddApcNet(this);
|
||||
}
|
||||
|
||||
protected override void AfterRemake(IEnumerable<INodeGroup> newGroups)
|
||||
{
|
||||
base.AfterRemake(newGroups);
|
||||
|
||||
foreach (var group in newGroups)
|
||||
{
|
||||
if (group is not ApcNetNodeGroup apcNet)
|
||||
continue;
|
||||
|
||||
apcNet.Powered = Powered;
|
||||
}
|
||||
|
||||
StopUpdates();
|
||||
}
|
||||
|
||||
protected override void OnGivingNodesForCombine(INodeGroup newGroup)
|
||||
{
|
||||
base.OnGivingNodesForCombine(newGroup);
|
||||
|
||||
if (newGroup is ApcNetNodeGroup apcNet)
|
||||
{
|
||||
apcNet.Powered = Powered;
|
||||
}
|
||||
|
||||
StopUpdates();
|
||||
}
|
||||
|
||||
private void StopUpdates()
|
||||
{
|
||||
EntitySystem.Get<ApcNetSystem>().RemoveApcNet(this);
|
||||
}
|
||||
|
||||
#region IApcNet Methods
|
||||
|
||||
protected override void SetNetConnectorNet(BaseApcNetComponent netConnectorComponent)
|
||||
{
|
||||
netConnectorComponent.Net = this;
|
||||
}
|
||||
|
||||
public void AddApc(ApcComponent apc)
|
||||
{
|
||||
if (!apc.Owner.TryGetComponent(out BatteryComponent? battery))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_apcBatteries.Add(apc, battery);
|
||||
}
|
||||
|
||||
public void RemoveApc(ApcComponent apc)
|
||||
{
|
||||
_apcBatteries.Remove(apc);
|
||||
}
|
||||
|
||||
public void AddPowerProvider(PowerProviderComponent provider)
|
||||
{
|
||||
_providers.Add(provider);
|
||||
|
||||
foreach (var receiver in provider.LinkedReceivers)
|
||||
{
|
||||
TotalPowerReceiverLoad += receiver.Load;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovePowerProvider(PowerProviderComponent provider)
|
||||
{
|
||||
_providers.Remove(provider);
|
||||
|
||||
foreach (var receiver in provider.LinkedReceivers)
|
||||
{
|
||||
TotalPowerReceiverLoad -= receiver.Load;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad)
|
||||
{
|
||||
DebugTools.Assert(_providers.Contains(provider));
|
||||
TotalPowerReceiverLoad -= oldLoad;
|
||||
TotalPowerReceiverLoad += newLoad;
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
var remainingPowerNeeded = TotalPowerReceiverLoad * frameTime;
|
||||
|
||||
foreach (var apcBatteryPair in _apcBatteries)
|
||||
{
|
||||
var apc = apcBatteryPair.Key;
|
||||
|
||||
if (!apc.MainBreakerEnabled)
|
||||
continue;
|
||||
|
||||
var battery = apcBatteryPair.Value;
|
||||
|
||||
if (battery.CurrentCharge < remainingPowerNeeded)
|
||||
{
|
||||
remainingPowerNeeded -= battery.CurrentCharge;
|
||||
battery.CurrentCharge = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
battery.UseCharge(remainingPowerNeeded);
|
||||
remainingPowerNeeded = 0;
|
||||
}
|
||||
|
||||
if (remainingPowerNeeded == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
Powered = remainingPowerNeeded == 0;
|
||||
}
|
||||
|
||||
private void SetPowered(bool powered)
|
||||
{
|
||||
if (powered != Powered)
|
||||
{
|
||||
_powered = powered;
|
||||
PoweredChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void PoweredChanged()
|
||||
{
|
||||
foreach (var provider in _providers)
|
||||
{
|
||||
foreach (var receiver in provider.LinkedReceivers)
|
||||
{
|
||||
receiver.ApcPowerChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTotalPowerReceiverLoad(int totalPowerReceiverLoad)
|
||||
{
|
||||
DebugTools.Assert(totalPowerReceiverLoad >= 0, $"Expected load equal to or greater than 0, was {totalPowerReceiverLoad}");
|
||||
_totalPowerReceiverLoad = totalPowerReceiverLoad;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class NullApcNet : IApcNet
|
||||
{
|
||||
/// <summary>
|
||||
/// It is important that this returns false, so <see cref="PowerProviderComponent"/>s with a <see cref="NullApcNet"/> have no power.
|
||||
/// </summary>
|
||||
public bool Powered => false;
|
||||
public GridId? GridId => default;
|
||||
public void AddApc(ApcComponent apc) { }
|
||||
public void AddPowerProvider(PowerProviderComponent provider) { }
|
||||
public void RemoveApc(ApcComponent apc) { }
|
||||
public void RemovePowerProvider(PowerProviderComponent provider) { }
|
||||
public void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad) { }
|
||||
public void Update(float frameTime) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameTicking;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.APC
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class ApcNetSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPauseManager _pauseManager = default!;
|
||||
|
||||
private HashSet<IApcNet> _apcNets = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var apcNet in _apcNets)
|
||||
{
|
||||
var gridId = apcNet.GridId;
|
||||
if (gridId != null && !_pauseManager.IsGridPaused(gridId.Value))
|
||||
apcNet.Update(frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddApcNet(ApcNetNodeGroup apcNet)
|
||||
{
|
||||
_apcNets.Add(apcNet);
|
||||
}
|
||||
|
||||
public void RemoveApcNet(ApcNetNodeGroup apcNet)
|
||||
{
|
||||
_apcNets.Remove(apcNet);
|
||||
}
|
||||
|
||||
public void Reset(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
// NodeGroupSystem does not remake ApcNets affected during restarting until a frame later,
|
||||
// when their grid is invalid. So, we are clearing them on round restart.
|
||||
_apcNets.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Server.Power.Components;
|
||||
|
||||
namespace Content.Server.APC.Components
|
||||
{
|
||||
public abstract class BaseApcNetComponent : BaseNetConnectorComponent<IApcNet>
|
||||
{
|
||||
protected override IApcNet NullNet => ApcNetNodeGroup.NullNet;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace Content.Server.Access.Components
|
||||
private ContainerSlot _targetIdContainer = default!;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(IdCardConsoleUiKey.Key);
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
private bool PrivilegedIDEmpty => _privilegedIdContainer.ContainedEntities.Count < 1;
|
||||
private bool TargetIDEmpty => _targetIdContainer.ContainedEntities.Count < 1;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.Server.Arcade.Components
|
||||
public override string Name => "BlockGameArcade";
|
||||
public override uint? NetID => ContentNetIDs.BLOCKGAME_ARCADE;
|
||||
|
||||
[ComponentDependency] private readonly PowerReceiverComponent? _powerReceiverComponent = default!;
|
||||
[ComponentDependency] private readonly ApcPowerReceiverComponent? _powerReceiverComponent = default!;
|
||||
|
||||
private bool Powered => _powerReceiverComponent?.Powered ?? false;
|
||||
private BoundUserInterface? UserInterface => Owner.GetUIOrNull(BlockGameUiKey.Key);
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Server.VendingMachines;
|
||||
using Content.Server.Wires.Components;
|
||||
using Content.Server.WireHacking;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Arcade;
|
||||
using Content.Shared.Interaction;
|
||||
@@ -28,7 +28,7 @@ namespace Content.Server.Arcade.Components
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = null!;
|
||||
|
||||
[ComponentDependency] private readonly PowerReceiverComponent? _powerReceiverComponent = default!;
|
||||
[ComponentDependency] private readonly ApcPowerReceiverComponent? _powerReceiverComponent = default!;
|
||||
[ComponentDependency] private readonly WiresComponent? _wiresComponent = default!;
|
||||
|
||||
private bool Powered => _powerReceiverComponent != null && _powerReceiverComponent.Powered;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Content.Server.GameObjects.Components
|
||||
protected readonly object UserInterfaceKey;
|
||||
|
||||
[ViewVariables] protected BoundUserInterface? UserInterface => Owner.GetUIOrNull(UserInterfaceKey);
|
||||
[ViewVariables] public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables] public bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
public BaseComputerUserInterfaceComponent(object key)
|
||||
{
|
||||
|
||||
@@ -4,9 +4,9 @@ using System;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Respiratory;
|
||||
using Content.Server.Explosion;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Actions;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using Content.Shared.Maps;
|
||||
using JetBrains.Annotations;
|
||||
@@ -33,6 +34,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesAfter.Add(typeof(NodeGroupSystem));
|
||||
|
||||
InitializeGases();
|
||||
InitializeCVars();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Construction.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Trinary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Trinary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -4,9 +4,9 @@ using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Atmos;
|
||||
@@ -62,7 +62,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
return;
|
||||
|
||||
// Create a pipenet if we don't have one already.
|
||||
portNode.TryAssignGroupIfNeeded();
|
||||
portNode.CreateSingleNetImmediate();
|
||||
Get<AtmosphereSystem>().Merge(portNode.Air, canister.InitialMixture);
|
||||
portNode.Air.Temperature = canister.InitialMixture.Temperature;
|
||||
portNode.Volume = canister.InitialMixture.Volume;
|
||||
@@ -90,7 +90,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
}
|
||||
|
||||
ui.SetState(new GasCanisterBoundUserInterfaceState(metadata.EntityName, portNode.Air.Pressure,
|
||||
portNode.NodeGroup.Nodes.Count > 1, tankLabel, tankPressure,
|
||||
portNode.NodeGroup!.Nodes.Count > 1, tankLabel, tankPressure,
|
||||
canister.ReleasePressure, canister.ReleaseValve,
|
||||
canister.MinReleasePressure, canister.MaxReleasePressure));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -2,8 +2,8 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Atmos.Piping.Binary.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.Construction.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Visuals;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -2,8 +2,8 @@ using System;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Atmos.Piping.Unary.Components;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Piping.Unary.Visuals;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Content.Server.BarSign
|
||||
}
|
||||
}
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
private void UpdateSignInfo()
|
||||
{
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Server.Power.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Battery.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class BatteryDischargerSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var comp in ComponentManager.EntityQuery<BatteryDischargerComponent>(false))
|
||||
{
|
||||
comp.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Server.Power.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Battery.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class BatteryStorageSystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var comp in ComponentManager.EntityQuery<BatteryStorageComponent>(false))
|
||||
{
|
||||
comp.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Server.Battery.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Battery.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class BatterySystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var comp in ComponentManager.EntityQuery<BatteryComponent>(true))
|
||||
{
|
||||
comp.OnUpdate(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Content.Server.Botany.Components
|
||||
[RegisterComponent]
|
||||
public class SeedExtractorComponent : Component, IInteractUsing
|
||||
{
|
||||
[ComponentDependency] private readonly PowerReceiverComponent? _powerReceiver = default!;
|
||||
[ComponentDependency] private readonly ApcPowerReceiverComponent? _powerReceiver = default!;
|
||||
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Content.Server.Cargo.Components
|
||||
[DataField("requestOnly")]
|
||||
private bool _requestOnly = false;
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private CargoConsoleSystem _cargoConsoleSystem = default!;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(CargoConsoleUiKey.Key);
|
||||
@@ -171,7 +171,7 @@ namespace Content.Server.Cargo.Components
|
||||
{
|
||||
foreach (IEntity entity in enumerator)
|
||||
{
|
||||
if (entity.HasComponent<CargoTelepadComponent>() && entity.TryGetComponent<PowerReceiverComponent>(out var powerReceiver) && powerReceiver.Powered)
|
||||
if (entity.HasComponent<CargoTelepadComponent>() && entity.TryGetComponent<ApcPowerReceiverComponent>(out var powerReceiver) && powerReceiver.Powered)
|
||||
{
|
||||
cargoTelepad = entity;
|
||||
break;
|
||||
|
||||
@@ -43,14 +43,14 @@ namespace Content.Server.Cargo.Components
|
||||
{
|
||||
if (args.Powered && _currentState == CargoTelepadState.Unpowered) {
|
||||
_currentState = CargoTelepadState.Idle;
|
||||
if(Owner.TryGetComponent<SpriteComponent>(out var spriteComponent))
|
||||
if(Owner.TryGetComponent<SpriteComponent>(out var spriteComponent) && spriteComponent.LayerCount > 0)
|
||||
spriteComponent.LayerSetState(0, "idle");
|
||||
TeleportLoop();
|
||||
}
|
||||
else if (!args.Powered)
|
||||
{
|
||||
_currentState = CargoTelepadState.Unpowered;
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent))
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent) && spriteComponent.LayerCount > 0)
|
||||
spriteComponent.LayerSetState(0, "offline");
|
||||
}
|
||||
}
|
||||
@@ -59,14 +59,14 @@ namespace Content.Server.Cargo.Components
|
||||
if (_currentState == CargoTelepadState.Idle && _teleportQueue.Count > 0)
|
||||
{
|
||||
_currentState = CargoTelepadState.Charging;
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent))
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent) && spriteComponent.LayerCount > 0)
|
||||
spriteComponent.LayerSetState(0, "idle");
|
||||
Owner.SpawnTimer((int) (TeleportDelay * 1000), () =>
|
||||
{
|
||||
if (!Deleted && !Owner.Deleted && _currentState == CargoTelepadState.Charging && _teleportQueue.Count > 0)
|
||||
{
|
||||
_currentState = CargoTelepadState.Teleporting;
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent))
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent) && spriteComponent.LayerCount > 0)
|
||||
spriteComponent.LayerSetState(0, "beam");
|
||||
Owner.SpawnTimer((int) (TeleportDuration * 1000), () =>
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace Content.Server.Cargo.Components
|
||||
SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/phasein.ogg", Owner, AudioParams.Default.WithVolume(-8f));
|
||||
Owner.EntityManager.SpawnEntity(_teleportQueue[0].Product, Owner.Transform.Coordinates);
|
||||
_teleportQueue.RemoveAt(0);
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent))
|
||||
if (Owner.TryGetComponent<SpriteComponent>(out var spriteComponent) && spriteComponent.LayerCount > 0)
|
||||
spriteComponent.LayerSetState(0, "idle");
|
||||
_currentState = CargoTelepadState.Idle;
|
||||
TeleportLoop();
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Content.Server.Chemistry.Components
|
||||
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
[ViewVariables] private bool _bufferModeTransfer = true;
|
||||
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables] private readonly Solution BufferSolution = new();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Content.Server.Chemistry.Components
|
||||
[ViewVariables] private ReagentUnit _dispenseAmount = ReagentUnit.New(10);
|
||||
[UsedImplicitly] [ViewVariables] private SolutionContainerComponent? Solution => _beakerContainer.ContainedEntity?.GetComponent<SolutionContainerComponent>();
|
||||
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentDispenserUiKey.Key);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Content.Server.Cloning
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var (cloning, power) in ComponentManager.EntityQuery<CloningPodComponent, PowerReceiverComponent>(true))
|
||||
foreach (var (cloning, power) in ComponentManager.EntityQuery<CloningPodComponent, ApcPowerReceiverComponent>(true))
|
||||
{
|
||||
if (cloning.UiKnownPowerState != power.Powered)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.Cloning.Components
|
||||
[Dependency] private readonly EuiManager _euiManager = null!;
|
||||
|
||||
[ViewVariables]
|
||||
public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
public bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
public BoundUserInterface? UserInterface =>
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Content.Server.Communications
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
private RoundEndSystem RoundEndSystem => EntitySystem.Get<RoundEndSystem>();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Content.Server.Computer
|
||||
// Let's ensure the container manager and container are here.
|
||||
Owner.EnsureContainer<Container>("board", out var _);
|
||||
|
||||
if (Owner.TryGetComponent(out PowerReceiverComponent? powerReceiver) &&
|
||||
if (Owner.TryGetComponent(out ApcPowerReceiverComponent? powerReceiver) &&
|
||||
Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(ComputerVisuals.Powered, powerReceiver.Powered);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.Wires.Components;
|
||||
using Content.Server.WireHacking;
|
||||
using Content.Shared.Construction;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.Wires.Components;
|
||||
using Content.Server.WireHacking;
|
||||
using Content.Shared.Construction;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Content.Server.Conveyor
|
||||
{
|
||||
public override string Name => "Conveyor";
|
||||
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
/// <summary>
|
||||
/// The angle to move entities by in relation to the owner's rotation.
|
||||
@@ -105,7 +105,7 @@ namespace Content.Server.Conveyor
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) &&
|
||||
if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
|
||||
!receiver.Powered)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.DeviceNetwork.Connections
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_owner.TryGetComponent<PowerReceiverComponent>(out var powerReceiver)
|
||||
if (_owner.TryGetComponent<ApcPowerReceiverComponent>(out var powerReceiver)
|
||||
&& TryGetWireNet(powerReceiver, out var ownNet)
|
||||
&& metadata.TryParseMetadata<INodeGroup>(WIRENET, out var senderNet))
|
||||
{
|
||||
@@ -44,7 +44,7 @@ namespace Content.Server.DeviceNetwork.Connections
|
||||
return new Metadata();
|
||||
}
|
||||
|
||||
if (_owner.TryGetComponent<PowerReceiverComponent>(out var powerReceiver)
|
||||
if (_owner.TryGetComponent<ApcPowerReceiverComponent>(out var powerReceiver)
|
||||
&& TryGetWireNet(powerReceiver, out var net))
|
||||
{
|
||||
var metadata = new Metadata
|
||||
@@ -63,16 +63,16 @@ namespace Content.Server.DeviceNetwork.Connections
|
||||
return payload;
|
||||
}
|
||||
|
||||
private bool TryGetWireNet(PowerReceiverComponent powerReceiver, [NotNullWhen(true)] out INodeGroup? net)
|
||||
private bool TryGetWireNet(ApcPowerReceiverComponent apcPowerReceiver, [NotNullWhen(true)] out INodeGroup? net)
|
||||
{
|
||||
if (powerReceiver.Provider is PowerProviderComponent provider &&
|
||||
provider.ProviderOwner.TryGetComponent<NodeContainerComponent>(out var nodeContainer))
|
||||
var provider = apcPowerReceiver.Provider;
|
||||
if (provider != null && provider.ProviderOwner.TryGetComponent<NodeContainerComponent>(out var nodeContainer))
|
||||
{
|
||||
var nodes = nodeContainer.Nodes;
|
||||
|
||||
foreach (var node in nodes.Values)
|
||||
{
|
||||
if (node.NodeGroupID == NodeGroupID.WireNet)
|
||||
if (node.NodeGroupID == NodeGroupID.WireNet && node.NodeGroup != null)
|
||||
{
|
||||
net = node.NodeGroup;
|
||||
return true;
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Content.Server.Disposal.Mailing
|
||||
|
||||
[ViewVariables]
|
||||
public bool Powered =>
|
||||
!Owner.TryGetComponent(out PowerReceiverComponent? receiver) ||
|
||||
!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) ||
|
||||
receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
@@ -372,7 +372,7 @@ namespace Content.Server.Disposal.Mailing
|
||||
|
||||
private void TogglePower()
|
||||
{
|
||||
if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||
if (!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Content.Server.Disposal.Unit.Components
|
||||
|
||||
[ViewVariables]
|
||||
public bool Powered =>
|
||||
!Owner.TryGetComponent(out PowerReceiverComponent? receiver) ||
|
||||
!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) ||
|
||||
receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
@@ -314,7 +314,7 @@ namespace Content.Server.Disposal.Unit.Components
|
||||
|
||||
private void TogglePower()
|
||||
{
|
||||
if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||
if (!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System;
|
||||
using System.Threading;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.VendingMachines;
|
||||
using Content.Server.Wires.Components;
|
||||
using Content.Server.WireHacking;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification;
|
||||
@@ -36,7 +36,7 @@ namespace Content.Server.Doors.Components
|
||||
private readonly SharedAppearanceComponent? _appearanceComponent = null;
|
||||
|
||||
[ComponentDependency]
|
||||
private readonly PowerReceiverComponent? _receiverComponent = null;
|
||||
private readonly ApcPowerReceiverComponent? _receiverComponent = null;
|
||||
|
||||
[ComponentDependency]
|
||||
private readonly WiresComponent? _wiresComponent = null;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.Gravity
|
||||
|
||||
private GravityGeneratorStatus _status;
|
||||
|
||||
public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
public bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
public bool SwitchedOn => _switchedOn;
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ namespace Content.Server.IoC
|
||||
IoCManager.Register<ActionManager, ActionManager>();
|
||||
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
||||
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
||||
IoCManager.Register<IPowerNetManager, PowerNetManager>();
|
||||
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
||||
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
||||
IoCManager.Register<IAccentManager, AccentManager>();
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Content.Server.Kitchen.Components
|
||||
[ViewVariables]
|
||||
private uint _currentCookTimerTime = 1;
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool _hasContents => Owner.TryGetComponent(out SolutionContainerComponent? solution) && (solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0);
|
||||
private bool _uiDirty = true;
|
||||
private bool _lostPower = false;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Content.Server.Kitchen.Components
|
||||
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentGrinderUiKey.Key);
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
/// <summary>
|
||||
/// Should the BoundUI be told to update?
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Content.Server.Lathe.Components
|
||||
[ViewVariables]
|
||||
private LatheRecipePrototype? _producingRecipe;
|
||||
[ViewVariables]
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
private static readonly TimeSpan InsertionTime = TimeSpan.FromSeconds(0.9f);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Light.Component;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -60,7 +60,7 @@ namespace Content.Server.Light.Components
|
||||
/// </summary>
|
||||
public void UpdateState()
|
||||
{
|
||||
if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||
if (!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace Content.Server.Light.Components
|
||||
|
||||
public void OnUpdate(float frameTime)
|
||||
{
|
||||
if (Owner.Deleted || !Owner.TryGetComponent(out BatteryComponent? battery))
|
||||
if (Owner.Deleted || !Owner.TryGetComponent(out BatteryComponent? battery) || Owner.Paused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -96,9 +96,9 @@ namespace Content.Server.Light.Components
|
||||
else
|
||||
{
|
||||
battery.CurrentCharge += _chargingWattage * frameTime * _chargingEfficiency;
|
||||
if (battery.BatteryState == BatteryState.Full)
|
||||
if (battery.IsFullyCharged)
|
||||
{
|
||||
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||
if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver))
|
||||
{
|
||||
receiver.Load = 1;
|
||||
}
|
||||
@@ -110,28 +110,24 @@ namespace Content.Server.Light.Components
|
||||
|
||||
private void TurnOff()
|
||||
{
|
||||
if (Owner.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
sprite.LayerSetState(0, "emergency_light_off");
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
light.Enabled = false;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||
appearance.SetData(EmergencyLightVisuals.On, false);
|
||||
}
|
||||
|
||||
private void TurnOn()
|
||||
{
|
||||
if (Owner.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
sprite.LayerSetState(0, "emergency_light_on");
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out PointLightComponent? light))
|
||||
{
|
||||
light.Enabled = true;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||
appearance.SetData(EmergencyLightVisuals.On, true);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Content.Server.Light.Components
|
||||
/// </summary>
|
||||
public void UpdateLight()
|
||||
{
|
||||
var powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||
var powerReceiver = Owner.GetComponent<ApcPowerReceiverComponent>();
|
||||
|
||||
if (LightBulb == null) // No light bulb.
|
||||
{
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Content.Server.Medical.Components
|
||||
private readonly Vector2 _ejectOffset = new(0f, 0f);
|
||||
|
||||
[ViewVariables]
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables]
|
||||
private BoundUserInterface? UserInterface => Owner.GetUIOrNull(MedicalScannerUiKey.Key);
|
||||
|
||||
|
||||
@@ -11,16 +11,51 @@ namespace Content.Server.NodeContainer.EntitySystems
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NodeContainerComponent, ComponentInit>(OnInitEvent);
|
||||
SubscribeLocalEvent<NodeContainerComponent, ComponentStartup>(OnStartupEvent);
|
||||
SubscribeLocalEvent<NodeContainerComponent, ComponentShutdown>(OnShutdownEvent);
|
||||
SubscribeLocalEvent<NodeContainerComponent, AnchorStateChangedEvent>(OnAnchorStateChanged);
|
||||
SubscribeLocalEvent<NodeContainerComponent, RotateEvent>(OnRotateEvent);
|
||||
}
|
||||
|
||||
private void OnAnchorStateChanged(EntityUid uid, NodeContainerComponent component, AnchorStateChangedEvent args)
|
||||
private static void OnInitEvent(EntityUid uid, NodeContainerComponent component, ComponentInit args)
|
||||
{
|
||||
component.AnchorUpdate();
|
||||
foreach (var (key, node) in component.Nodes)
|
||||
{
|
||||
node.Name = key;
|
||||
node.Initialize(component.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRotateEvent(EntityUid uid, NodeContainerComponent container, RotateEvent ev)
|
||||
private static void OnStartupEvent(EntityUid uid, NodeContainerComponent component, ComponentStartup args)
|
||||
{
|
||||
foreach (var node in component.Nodes.Values)
|
||||
{
|
||||
node.OnContainerStartup();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnShutdownEvent(EntityUid uid, NodeContainerComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var node in component.Nodes.Values)
|
||||
{
|
||||
node.OnContainerShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAnchorStateChanged(
|
||||
EntityUid uid,
|
||||
NodeContainerComponent component,
|
||||
AnchorStateChangedEvent args)
|
||||
{
|
||||
foreach (var node in component.Nodes.Values)
|
||||
{
|
||||
node.AnchorUpdate();
|
||||
node.AnchorStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnRotateEvent(EntityUid uid, NodeContainerComponent container, RotateEvent ev)
|
||||
{
|
||||
if (ev.NewRotation == ev.OldRotation)
|
||||
{
|
||||
|
||||
@@ -1,30 +1,385 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.NodeContainer;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.NodeContainer.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class NodeGroupSystem : EntitySystem
|
||||
{
|
||||
private readonly HashSet<INodeGroup> _dirtyNodeGroups = new();
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public void AddDirtyNodeGroup(INodeGroup nodeGroup)
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly INodeGroupFactory _nodeGroupFactory = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
|
||||
private readonly List<int> _visDeletes = new();
|
||||
private readonly List<BaseNodeGroup> _visSends = new();
|
||||
|
||||
private readonly HashSet<IPlayerSession> _visPlayers = new();
|
||||
private readonly HashSet<BaseNodeGroup> _toRemake = new();
|
||||
private readonly HashSet<Node> _toRemove = new();
|
||||
private readonly List<Node> _toReflood = new();
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public bool VisEnabled => _visPlayers.Count != 0;
|
||||
|
||||
private int _gen = 1;
|
||||
private int _groupNetIdCounter = 1;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_dirtyNodeGroups.Add(nodeGroup);
|
||||
base.Initialize();
|
||||
|
||||
_sawmill = _logManager.GetSawmill("nodegroup");
|
||||
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
|
||||
SubscribeNetworkEvent<NodeVis.MsgEnable>(HandleEnableMsg);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
private void HandleEnableMsg(NodeVis.MsgEnable msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var session = (IPlayerSession) args.SenderSession;
|
||||
if (!_adminManager.HasAdminFlag(session, AdminFlags.Debug))
|
||||
return;
|
||||
|
||||
if (msg.Enabled)
|
||||
{
|
||||
_visPlayers.Add(session);
|
||||
VisSendFullStateImmediate(session);
|
||||
}
|
||||
else
|
||||
{
|
||||
_visPlayers.Remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus == SessionStatus.Disconnected)
|
||||
_visPlayers.Remove(e.Session);
|
||||
}
|
||||
|
||||
public void QueueRemakeGroup(BaseNodeGroup group)
|
||||
{
|
||||
if (group.Remaking)
|
||||
return;
|
||||
|
||||
_toRemake.Add(group);
|
||||
group.Remaking = true;
|
||||
|
||||
foreach (var node in group.Nodes)
|
||||
{
|
||||
QueueReflood(node);
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueReflood(Node node)
|
||||
{
|
||||
if (node.FlaggedForFlood)
|
||||
return;
|
||||
|
||||
_toReflood.Add(node);
|
||||
node.FlaggedForFlood = true;
|
||||
}
|
||||
|
||||
public void QueueNodeRemove(Node node)
|
||||
{
|
||||
_toRemove.Add(node);
|
||||
}
|
||||
|
||||
public void CreateSingleNetImmediate(Node node)
|
||||
{
|
||||
if (node.NodeGroup != null)
|
||||
return;
|
||||
|
||||
QueueReflood(node);
|
||||
|
||||
InitGroup(node, new List<Node> {node});
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var group in _dirtyNodeGroups)
|
||||
DoGroupUpdates();
|
||||
VisDoUpdate();
|
||||
}
|
||||
|
||||
private void DoGroupUpdates()
|
||||
{
|
||||
// "Why is there a separate queue for group remakes and node refloods when they both cause eachother"
|
||||
// Future planning for the potential ability to do more intelligent group updating.
|
||||
|
||||
if (_toRemake.Count == 0 && _toReflood.Count == 0 && _toRemove.Count == 0)
|
||||
return;
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
foreach (var toRemove in _toRemove)
|
||||
{
|
||||
group.RemakeGroup();
|
||||
if (toRemove.NodeGroup == null)
|
||||
continue;
|
||||
|
||||
var group = (BaseNodeGroup) toRemove.NodeGroup;
|
||||
|
||||
group.RemoveNode(toRemove);
|
||||
toRemove.NodeGroup = null;
|
||||
|
||||
QueueRemakeGroup(group);
|
||||
}
|
||||
|
||||
_dirtyNodeGroups.Clear();
|
||||
// Break up all remaking groups.
|
||||
// Don't clear the list yet, we'll come back to these later.
|
||||
foreach (var toRemake in _toRemake)
|
||||
{
|
||||
QueueRemakeGroup(toRemake);
|
||||
}
|
||||
|
||||
_gen += 1;
|
||||
|
||||
// Go over all nodes to calculate reachable nodes and make an undirected graph out of them.
|
||||
// Node.GetReachableNodes() may return results asymmetrically,
|
||||
// i.e. node A may return B, but B may not return A.
|
||||
//
|
||||
// Must be for loop to allow concurrent modification from RemakeGroupImmediate.
|
||||
for (var i = 0; i < _toReflood.Count; i++)
|
||||
{
|
||||
var node = _toReflood[i];
|
||||
|
||||
if (node.Deleting)
|
||||
continue;
|
||||
|
||||
ClearReachableIfNecessary(node);
|
||||
|
||||
if (node.NodeGroup?.Remaking == false)
|
||||
{
|
||||
QueueRemakeGroup((BaseNodeGroup) node.NodeGroup);
|
||||
}
|
||||
|
||||
foreach (var compatible in GetCompatibleNodes(node))
|
||||
{
|
||||
ClearReachableIfNecessary(compatible);
|
||||
|
||||
if (compatible.NodeGroup?.Remaking == false)
|
||||
{
|
||||
// We are expanding into an existing group,
|
||||
// remake it so that we can treat it uniformly.
|
||||
var group = (BaseNodeGroup) compatible.NodeGroup;
|
||||
QueueRemakeGroup(group);
|
||||
}
|
||||
|
||||
node.ReachableNodes.Add(compatible);
|
||||
compatible.ReachableNodes.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
var newGroups = new List<BaseNodeGroup>();
|
||||
|
||||
// Flood fill over nodes. Every node will only be flood filled once.
|
||||
foreach (var node in _toReflood)
|
||||
{
|
||||
node.FlaggedForFlood = false;
|
||||
|
||||
// Check if already flood filled.
|
||||
if (node.FloodGen == _gen || node.Deleting)
|
||||
continue;
|
||||
|
||||
// Flood fill
|
||||
var groupNodes = FloodFillNode(node);
|
||||
|
||||
var newGroup = InitGroup(node, groupNodes);
|
||||
newGroups.Add(newGroup);
|
||||
}
|
||||
|
||||
// Go over dead groups that need to be cleaned up.
|
||||
// Tell them to push their data to new groups too.
|
||||
foreach (var oldGroup in _toRemake)
|
||||
{
|
||||
// Group by the NEW group.
|
||||
var newGrouped = oldGroup.Nodes.GroupBy(n => n.NodeGroup);
|
||||
|
||||
oldGroup.Removed = true;
|
||||
oldGroup.AfterRemake(newGrouped);
|
||||
if (VisEnabled)
|
||||
_visDeletes.Add(oldGroup.NetId);
|
||||
}
|
||||
|
||||
var refloodCount = _toReflood.Count;
|
||||
|
||||
_toReflood.Clear();
|
||||
_toRemake.Clear();
|
||||
_toRemove.Clear();
|
||||
|
||||
foreach (var group in newGroups)
|
||||
{
|
||||
foreach (var node in group.Nodes)
|
||||
{
|
||||
node.OnPostRebuild();
|
||||
}
|
||||
}
|
||||
|
||||
_sawmill.Debug($"Updated node groups in {sw.Elapsed.TotalMilliseconds}ms. {newGroups.Count} new groups, {refloodCount} nodes processed.");
|
||||
}
|
||||
|
||||
private void ClearReachableIfNecessary(Node node)
|
||||
{
|
||||
if (node.UndirectGen != _gen)
|
||||
{
|
||||
node.ReachableNodes.Clear();
|
||||
node.UndirectGen = _gen;
|
||||
}
|
||||
}
|
||||
|
||||
private BaseNodeGroup InitGroup(Node node, List<Node> groupNodes)
|
||||
{
|
||||
var newGroup = (BaseNodeGroup) _nodeGroupFactory.MakeNodeGroup(node.NodeGroupID);
|
||||
newGroup.Initialize(node);
|
||||
newGroup.NetId = _groupNetIdCounter++;
|
||||
|
||||
var netIdCounter = 0;
|
||||
foreach (var groupNode in groupNodes)
|
||||
{
|
||||
groupNode.NodeGroup = newGroup;
|
||||
groupNode.NetId = ++netIdCounter;
|
||||
}
|
||||
|
||||
newGroup.LoadNodes(groupNodes);
|
||||
|
||||
if (VisEnabled)
|
||||
_visSends.Add(newGroup);
|
||||
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
private List<Node> FloodFillNode(Node rootNode)
|
||||
{
|
||||
// All nodes we're filling into that currently have NO network.
|
||||
var allNodes = new List<Node>();
|
||||
|
||||
var stack = new Stack<Node>();
|
||||
stack.Push(rootNode);
|
||||
rootNode.FloodGen = _gen;
|
||||
|
||||
while (stack.TryPop(out var node))
|
||||
{
|
||||
allNodes.Add(node);
|
||||
|
||||
foreach (var reachable in node.ReachableNodes)
|
||||
{
|
||||
if (reachable.FloodGen == _gen)
|
||||
continue;
|
||||
|
||||
reachable.FloodGen = _gen;
|
||||
stack.Push(reachable);
|
||||
}
|
||||
}
|
||||
|
||||
return allNodes;
|
||||
}
|
||||
|
||||
private static IEnumerable<Node> GetCompatibleNodes(Node node)
|
||||
{
|
||||
foreach (var reachable in node.GetReachableNodes())
|
||||
{
|
||||
DebugTools.Assert(reachable != node, "GetReachableNodes() should not include self.");
|
||||
|
||||
if (reachable.Connectable && reachable.NodeGroupID == node.NodeGroupID)
|
||||
yield return reachable;
|
||||
}
|
||||
}
|
||||
|
||||
private void VisDoUpdate()
|
||||
{
|
||||
if (_visSends.Count == 0 && _visDeletes.Count == 0)
|
||||
return;
|
||||
|
||||
var msg = new NodeVis.MsgData();
|
||||
|
||||
msg.GroupDeletions.AddRange(_visDeletes);
|
||||
msg.Groups.AddRange(_visSends.Select(VisMakeGroupState));
|
||||
|
||||
_visSends.Clear();
|
||||
_visDeletes.Clear();
|
||||
|
||||
foreach (var player in _visPlayers)
|
||||
{
|
||||
RaiseNetworkEvent(msg, player.ConnectedClient);
|
||||
}
|
||||
}
|
||||
|
||||
private void VisSendFullStateImmediate(IPlayerSession player)
|
||||
{
|
||||
var msg = new NodeVis.MsgData();
|
||||
|
||||
var allNetworks = ComponentManager
|
||||
.EntityQuery<NodeContainerComponent>()
|
||||
.SelectMany(nc => nc.Nodes.Values)
|
||||
.Select(n => (BaseNodeGroup?) n.NodeGroup)
|
||||
.Where(n => n != null)
|
||||
.Distinct();
|
||||
|
||||
foreach (var network in allNetworks)
|
||||
{
|
||||
msg.Groups.Add(VisMakeGroupState(network!));
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(msg, player.ConnectedClient);
|
||||
}
|
||||
|
||||
private static NodeVis.GroupData VisMakeGroupState(BaseNodeGroup group)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
NetId = group.NetId,
|
||||
GroupId = group.GroupId.ToString(),
|
||||
Color = CalcNodeGroupColor(group),
|
||||
Nodes = group.Nodes.Select(n => new NodeVis.NodeDatum
|
||||
{
|
||||
Name = n.Name,
|
||||
NetId = n.NetId,
|
||||
Reachable = n.ReachableNodes.Select(r => r.NetId).ToArray(),
|
||||
Entity = n.Owner.Uid,
|
||||
Type = n.GetType().Name
|
||||
}).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
private static Color CalcNodeGroupColor(BaseNodeGroup group)
|
||||
{
|
||||
return group.GroupId switch
|
||||
{
|
||||
NodeGroupID.HVPower => Color.Orange,
|
||||
NodeGroupID.MVPower => Color.Yellow,
|
||||
NodeGroupID.Apc => Color.LimeGreen,
|
||||
NodeGroupID.AMEngine => Color.Purple,
|
||||
NodeGroupID.Pipe => Color.Blue,
|
||||
NodeGroupID.WireNet => Color.DarkMagenta,
|
||||
_ => Color.White
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,60 +20,18 @@ namespace Content.Server.NodeContainer
|
||||
{
|
||||
public override string Name => "NodeContainer";
|
||||
|
||||
[ViewVariables]
|
||||
public IReadOnlyDictionary<string, Node> Nodes => _nodes;
|
||||
[DataField("nodes")] [ViewVariables] public Dictionary<string, Node> Nodes { get; } = new();
|
||||
|
||||
[DataField("nodes")]
|
||||
private readonly Dictionary<string, Node> _nodes = new();
|
||||
|
||||
[DataField("examinable")]
|
||||
private bool _examinable = false;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
foreach (var node in _nodes.Values)
|
||||
{
|
||||
node.Initialize(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
foreach (var node in _nodes.Values)
|
||||
{
|
||||
node.OnContainerStartup();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
foreach (var node in _nodes.Values)
|
||||
{
|
||||
node.OnContainerShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void AnchorUpdate()
|
||||
{
|
||||
foreach (var node in Nodes.Values)
|
||||
{
|
||||
node.AnchorUpdate();
|
||||
node.AnchorStateChanged();
|
||||
}
|
||||
}
|
||||
[DataField("examinable")] private bool _examinable = false;
|
||||
|
||||
public T GetNode<T>(string identifier) where T : Node
|
||||
{
|
||||
return (T)_nodes[identifier];
|
||||
return (T) Nodes[identifier];
|
||||
}
|
||||
|
||||
public bool TryGetNode<T>(string identifier, [NotNullWhen(true)] out T? node) where T : Node
|
||||
{
|
||||
if (_nodes.TryGetValue(identifier, out var n) && n is T t)
|
||||
if (Nodes.TryGetValue(identifier, out var n) && n is T t)
|
||||
{
|
||||
node = t;
|
||||
return true;
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.Power.Components;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
public abstract class BaseNetConnectorNodeGroup<TNetConnector, TNetType> : BaseNodeGroup where TNetConnector : BaseNetConnectorComponent<TNetType>
|
||||
{
|
||||
private readonly Dictionary<Node, List<TNetConnector>> _netConnectorComponents = new();
|
||||
|
||||
protected override void OnAddNode(Node node)
|
||||
{
|
||||
var newNetConnectorComponents = node.Owner
|
||||
.GetAllComponents<TNetConnector>()
|
||||
.Where(powerComp => (NodeGroupID) powerComp.Voltage == node.NodeGroupID)
|
||||
.ToList();
|
||||
_netConnectorComponents[node] = newNetConnectorComponents;
|
||||
foreach (var netConnectorComponent in newNetConnectorComponents)
|
||||
{
|
||||
SetNetConnectorNet(netConnectorComponent);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void SetNetConnectorNet(TNetConnector netConnectorComponent);
|
||||
|
||||
protected override void OnRemoveNode(Node node)
|
||||
{
|
||||
foreach (var netConnectorComponent in _netConnectorComponents[node])
|
||||
{
|
||||
netConnectorComponent.ClearNet();
|
||||
}
|
||||
_netConnectorComponents.Remove(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Content.Server/NodeContainer/NodeGroups/BaseNodeGroup.cs
Normal file
91
Content.Server/NodeContainer/NodeGroups/BaseNodeGroup.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a collection of <see cref="Node"/>s, and performs operations requiring a list of
|
||||
/// all connected <see cref="Node"/>s.
|
||||
/// </summary>
|
||||
public interface INodeGroup
|
||||
{
|
||||
bool Remaking { get; }
|
||||
|
||||
IReadOnlyList<Node> Nodes { get; }
|
||||
|
||||
void Create(NodeGroupID groupId);
|
||||
|
||||
void Initialize(Node sourceNode);
|
||||
|
||||
void RemoveNode(Node node);
|
||||
|
||||
void LoadNodes(List<Node> groupNodes);
|
||||
|
||||
// In theory, the SS13 curse ensures this method will never be called.
|
||||
void AfterRemake(IEnumerable<IGrouping<INodeGroup?, Node>> newGroups);
|
||||
|
||||
// TODO: Why is this method needed?
|
||||
void QueueRemake();
|
||||
}
|
||||
|
||||
[NodeGroup(NodeGroupID.Default, NodeGroupID.WireNet)]
|
||||
public class BaseNodeGroup : INodeGroup
|
||||
{
|
||||
public bool Remaking { get; set; }
|
||||
|
||||
IReadOnlyList<Node> INodeGroup.Nodes => Nodes;
|
||||
|
||||
[ViewVariables] public readonly List<Node> Nodes = new();
|
||||
|
||||
[ViewVariables] public int NodeCount => Nodes.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Debug variable to indicate that this NodeGroup should not be being used by anything.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Removed { get; set; } = false;
|
||||
|
||||
[ViewVariables]
|
||||
protected GridId GridId { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int NetId;
|
||||
|
||||
[ViewVariables]
|
||||
public NodeGroupID GroupId { get; private set; }
|
||||
|
||||
public void Create(NodeGroupID groupId)
|
||||
{
|
||||
GroupId = groupId;
|
||||
}
|
||||
|
||||
public virtual void Initialize(Node sourceNode)
|
||||
{
|
||||
// TODO: Can we get rid of this GridId?
|
||||
GridId = sourceNode.Owner.Transform.GridID;
|
||||
}
|
||||
|
||||
public virtual void RemoveNode(Node node)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void LoadNodes(
|
||||
List<Node> groupNodes)
|
||||
{
|
||||
Nodes.AddRange(groupNodes);
|
||||
}
|
||||
|
||||
public virtual void AfterRemake(IEnumerable<IGrouping<INodeGroup?, Node>> newGroups) { }
|
||||
|
||||
public void QueueRemake()
|
||||
{
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueRemakeGroup(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a collection of <see cref="Node"/>s, and performs operations requiring a list of
|
||||
/// all connected <see cref="Node"/>s.
|
||||
/// </summary>
|
||||
public interface INodeGroup
|
||||
{
|
||||
IReadOnlyList<Node> Nodes { get; }
|
||||
|
||||
void Initialize(Node sourceNode);
|
||||
|
||||
void AddNode(Node node);
|
||||
|
||||
void RemoveNode(Node node);
|
||||
|
||||
void CombineGroup(INodeGroup newGroup);
|
||||
|
||||
void RemakeGroup();
|
||||
}
|
||||
|
||||
[NodeGroup(NodeGroupID.Default, NodeGroupID.WireNet)]
|
||||
public class BaseNodeGroup : INodeGroup
|
||||
{
|
||||
[ViewVariables]
|
||||
public IReadOnlyList<Node> Nodes => _nodes;
|
||||
private readonly List<Node> _nodes = new();
|
||||
|
||||
[ViewVariables]
|
||||
public int NodeCount => Nodes.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Debug variable to indicate that this NodeGroup should not be being used by anything.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Removed { get; private set; } = false;
|
||||
|
||||
public static readonly INodeGroup NullGroup = new NullNodeGroup();
|
||||
|
||||
protected GridId GridId { get; private set;}
|
||||
|
||||
public virtual void Initialize(Node sourceNode)
|
||||
{
|
||||
GridId = sourceNode.Owner.Transform.GridID;
|
||||
}
|
||||
|
||||
public void AddNode(Node node)
|
||||
{
|
||||
_nodes.Add(node);
|
||||
OnAddNode(node);
|
||||
}
|
||||
|
||||
public void RemoveNode(Node node)
|
||||
{
|
||||
_nodes.Remove(node);
|
||||
OnRemoveNode(node);
|
||||
EntitySystem.Get<NodeGroupSystem>().AddDirtyNodeGroup(this);
|
||||
}
|
||||
|
||||
public void CombineGroup(INodeGroup newGroup)
|
||||
{
|
||||
if (newGroup.Nodes.Count < Nodes.Count)
|
||||
{
|
||||
newGroup.CombineGroup(this);
|
||||
return;
|
||||
}
|
||||
|
||||
OnGivingNodesForCombine(newGroup);
|
||||
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.NodeGroup = newGroup;
|
||||
}
|
||||
|
||||
Removed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Causes all <see cref="Node"/>s to remake their groups. Called when a <see cref="Node"/> is removed
|
||||
/// and may have split a group in two, so multiple new groups may need to be formed.
|
||||
/// </summary>
|
||||
public void RemakeGroup()
|
||||
{
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.ClearNodeGroup();
|
||||
}
|
||||
|
||||
var newGroups = new HashSet<INodeGroup>();
|
||||
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
if (node.TryAssignGroupIfNeeded())
|
||||
{
|
||||
node.SpreadGroup();
|
||||
newGroups.Add(node.NodeGroup);
|
||||
}
|
||||
}
|
||||
|
||||
AfterRemake(newGroups);
|
||||
|
||||
Removed = true;
|
||||
}
|
||||
|
||||
protected virtual void OnAddNode(Node node) { }
|
||||
|
||||
protected virtual void OnRemoveNode(Node node) { }
|
||||
|
||||
protected virtual void OnGivingNodesForCombine(INodeGroup newGroup) { }
|
||||
|
||||
protected virtual void AfterRemake(IEnumerable<INodeGroup> newGroups) { }
|
||||
|
||||
protected class NullNodeGroup : INodeGroup
|
||||
{
|
||||
public IReadOnlyList<Node> Nodes => _nodes;
|
||||
private readonly List<Node> _nodes = new();
|
||||
public void Initialize(Node sourceNode) { }
|
||||
public void AddNode(Node node) { }
|
||||
public void CombineGroup(INodeGroup newGroup) { }
|
||||
public void RemoveNode(Node node) { }
|
||||
public void RemakeGroup() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
@@ -9,6 +10,7 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
/// have the same type of <see cref="INodeGroup"/>. Used by <see cref="INodeGroupFactory"/>.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
[MeansImplicitUse]
|
||||
public class NodeGroupAttribute : Attribute
|
||||
{
|
||||
public NodeGroupID[] NodeGroupIDs { get; }
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="INodeGroup"/> instance.
|
||||
/// </summary>
|
||||
INodeGroup MakeNodeGroup(Node sourceNode);
|
||||
INodeGroup MakeNodeGroup(NodeGroupID id);
|
||||
}
|
||||
|
||||
public class NodeGroupFactory : INodeGroupFactory
|
||||
@@ -45,15 +45,14 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
}
|
||||
}
|
||||
|
||||
public INodeGroup MakeNodeGroup(Node sourceNode)
|
||||
public INodeGroup MakeNodeGroup(NodeGroupID id)
|
||||
{
|
||||
if (_groupTypes.TryGetValue(sourceNode.NodeGroupID, out var type))
|
||||
{
|
||||
var nodeGroup = _typeFactory.CreateInstance<INodeGroup>(type);
|
||||
nodeGroup.Initialize(sourceNode);
|
||||
return nodeGroup;
|
||||
}
|
||||
throw new ArgumentException($"{sourceNode.NodeGroupID} did not have an associated {nameof(INodeGroup)}.");
|
||||
if (!_groupTypes.TryGetValue(id, out var type))
|
||||
throw new ArgumentException($"{id} did not have an associated {nameof(INodeGroup)} implementation.");
|
||||
|
||||
var instance = _typeFactory.CreateInstance<INodeGroup>(type);
|
||||
instance.Create(id);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
@@ -24,17 +25,15 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
[NodeGroup(NodeGroupID.Pipe)]
|
||||
public class PipeNet : BaseNodeGroup, IPipeNet
|
||||
{
|
||||
[ViewVariables]
|
||||
public GasMixture Air { get; set; } = new() {Temperature = Atmospherics.T20C};
|
||||
[ViewVariables] public GasMixture Air { get; set; } = new() {Temperature = Atmospherics.T20C};
|
||||
|
||||
public static readonly IPipeNet NullNet = new NullPipeNet();
|
||||
|
||||
[ViewVariables]
|
||||
private readonly List<PipeNode> _pipes = new();
|
||||
[ViewVariables] private readonly List<PipeNode> _pipes = new();
|
||||
|
||||
[ViewVariables] private AtmosphereSystem? _atmosphereSystem;
|
||||
|
||||
[ViewVariables] private IGridAtmosphereComponent? GridAtmos => _atmosphereSystem?.GetGridAtmosphere(GridId);
|
||||
[ViewVariables]
|
||||
private IGridAtmosphereComponent? GridAtmos =>
|
||||
_atmosphereSystem?.GetGridAtmosphere(GridId);
|
||||
|
||||
public override void Initialize(Node sourceNode)
|
||||
{
|
||||
@@ -49,35 +48,30 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
_atmosphereSystem?.React(Air, this);
|
||||
}
|
||||
|
||||
protected override void OnAddNode(Node node)
|
||||
public override void LoadNodes(List<Node> groupNodes)
|
||||
{
|
||||
if (node is not PipeNode pipeNode)
|
||||
return;
|
||||
base.LoadNodes(groupNodes);
|
||||
|
||||
_pipes.Add(pipeNode);
|
||||
pipeNode.JoinPipeNet(this);
|
||||
Air.Volume += pipeNode.Volume;
|
||||
foreach (var node in groupNodes)
|
||||
{
|
||||
var pipeNode = (PipeNode) node;
|
||||
_pipes.Add(pipeNode);
|
||||
pipeNode.JoinPipeNet(this);
|
||||
Air.Volume += pipeNode.Volume;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRemoveNode(Node node)
|
||||
public override void RemoveNode(Node node)
|
||||
{
|
||||
RemoveFromGridAtmos();
|
||||
if (node is not PipeNode pipeNode)
|
||||
return;
|
||||
base.RemoveNode(node);
|
||||
|
||||
pipeNode.ClearPipeNet();
|
||||
var pipeNode = (PipeNode) node;
|
||||
Air.Volume -= pipeNode.Volume;
|
||||
// TODO: Bad O(n^2)
|
||||
_pipes.Remove(pipeNode);
|
||||
}
|
||||
|
||||
protected override void OnGivingNodesForCombine(INodeGroup newGroup)
|
||||
{
|
||||
if (newGroup is not IPipeNet newPipeNet)
|
||||
return;
|
||||
|
||||
EntitySystem.Get<AtmosphereSystem>().Merge(newPipeNet.Air, Air);
|
||||
}
|
||||
|
||||
protected override void AfterRemake(IEnumerable<INodeGroup> newGroups)
|
||||
public override void AfterRemake(IEnumerable<IGrouping<INodeGroup?, Node>> newGroups)
|
||||
{
|
||||
RemoveFromGridAtmos();
|
||||
|
||||
@@ -86,14 +80,15 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
|
||||
foreach (var newGroup in newGroups)
|
||||
{
|
||||
if (newGroup is not IPipeNet newPipeNet)
|
||||
if (newGroup.Key is not IPipeNet newPipeNet)
|
||||
continue;
|
||||
|
||||
var newAir = newPipeNet.Air;
|
||||
var newVolume = newGroup.Cast<PipeNode>().Sum(n => n.Volume);
|
||||
|
||||
buffer.Clear();
|
||||
atmosphereSystem.Merge(buffer, Air);
|
||||
buffer.Multiply(MathF.Min(newAir.Volume / Air.Volume, 1f));
|
||||
buffer.Multiply(MathF.Min(newVolume / Air.Volume, 1f));
|
||||
atmosphereSystem.Merge(newAir, buffer);
|
||||
}
|
||||
}
|
||||
@@ -102,20 +97,5 @@ namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
GridAtmos?.RemovePipeNet(this);
|
||||
}
|
||||
|
||||
private class NullPipeNet : NullNodeGroup, IPipeNet
|
||||
{
|
||||
private readonly GasMixture _air;
|
||||
|
||||
GasMixture IGasMixtureHolder.Air { get => _air; set { } }
|
||||
|
||||
public NullPipeNet()
|
||||
{
|
||||
_air = new GasMixture(1f) {Temperature = Atmospherics.T20C};
|
||||
_air.MarkImmutable();
|
||||
}
|
||||
|
||||
public void Update() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Content.Server.Power.Components;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.NodeContainer.NodeGroups
|
||||
{
|
||||
public interface IPowerNet
|
||||
{
|
||||
void AddSupplier(PowerSupplierComponent supplier);
|
||||
|
||||
void RemoveSupplier(PowerSupplierComponent supplier);
|
||||
|
||||
void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate);
|
||||
|
||||
void AddConsumer(PowerConsumerComponent consumer);
|
||||
|
||||
void RemoveConsumer(PowerConsumerComponent consumer);
|
||||
|
||||
void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate);
|
||||
|
||||
void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority);
|
||||
|
||||
void UpdateConsumerReceivedPower();
|
||||
}
|
||||
|
||||
[NodeGroup(NodeGroupID.HVPower, NodeGroupID.MVPower)]
|
||||
public class PowerNetNodeGroup : BaseNetConnectorNodeGroup<BasePowerNetComponent, IPowerNet>, IPowerNet
|
||||
{
|
||||
private static readonly Priority[] CachedPriorities = (Priority[]) Enum.GetValues(typeof(Priority));
|
||||
|
||||
[Dependency] private readonly IPowerNetManager _powerNetManager = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private readonly List<PowerSupplierComponent> _suppliers = new();
|
||||
|
||||
[ViewVariables]
|
||||
private int _totalSupply = 0;
|
||||
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<Priority, List<PowerConsumerComponent>> _consumersByPriority = new();
|
||||
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<Priority, int> _drawByPriority = new();
|
||||
|
||||
public static readonly IPowerNet NullNet = new NullPowerNet();
|
||||
|
||||
public PowerNetNodeGroup()
|
||||
{
|
||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||
{
|
||||
_consumersByPriority.Add(priority, new List<PowerConsumerComponent>());
|
||||
_drawByPriority.Add(priority, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetNetConnectorNet(BasePowerNetComponent netConnectorComponent)
|
||||
{
|
||||
netConnectorComponent.Net = this;
|
||||
}
|
||||
|
||||
#region IPowerNet Methods
|
||||
|
||||
public void AddSupplier(PowerSupplierComponent supplier)
|
||||
{
|
||||
_suppliers.Add(supplier);
|
||||
_totalSupply += supplier.SupplyRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void RemoveSupplier(PowerSupplierComponent supplier)
|
||||
{
|
||||
Debug.Assert(_suppliers.Contains(supplier));
|
||||
_suppliers.Remove(supplier);
|
||||
_totalSupply -= supplier.SupplyRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate)
|
||||
{
|
||||
Debug.Assert(_suppliers.Contains(supplier));
|
||||
_totalSupply -= oldSupplyRate;
|
||||
_totalSupply += newSupplyRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void AddConsumer(PowerConsumerComponent consumer)
|
||||
{
|
||||
_consumersByPriority[consumer.Priority].Add(consumer);
|
||||
_drawByPriority[consumer.Priority] += consumer.DrawRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void RemoveConsumer(PowerConsumerComponent consumer)
|
||||
{
|
||||
Debug.Assert(_consumersByPriority[consumer.Priority].Contains(consumer));
|
||||
consumer.ReceivedPower = 0;
|
||||
_consumersByPriority[consumer.Priority].Remove(consumer);
|
||||
_drawByPriority[consumer.Priority] -= consumer.DrawRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate)
|
||||
{
|
||||
Debug.Assert(_consumersByPriority[consumer.Priority].Contains(consumer));
|
||||
_drawByPriority[consumer.Priority] -= oldDrawRate;
|
||||
_drawByPriority[consumer.Priority] += newDrawRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority)
|
||||
{
|
||||
Debug.Assert(_consumersByPriority[oldPriority].Contains(consumer));
|
||||
_consumersByPriority[oldPriority].Remove(consumer);
|
||||
_drawByPriority[oldPriority] -= consumer.DrawRate;
|
||||
_consumersByPriority[newPriority].Add(consumer);
|
||||
_drawByPriority[newPriority] += consumer.DrawRate;
|
||||
_powerNetManager.AddDirtyPowerNet(this);
|
||||
}
|
||||
|
||||
public void UpdateConsumerReceivedPower()
|
||||
{
|
||||
var remainingSupply = _totalSupply;
|
||||
foreach (var priority in CachedPriorities)
|
||||
{
|
||||
var categoryPowerDemand = _drawByPriority[priority];
|
||||
if (remainingSupply >= categoryPowerDemand) //can fully power all in category
|
||||
{
|
||||
remainingSupply -= categoryPowerDemand;
|
||||
foreach (var consumer in _consumersByPriority[priority])
|
||||
{
|
||||
consumer.ReceivedPower = consumer.DrawRate;
|
||||
}
|
||||
}
|
||||
else //cannot fully power all, split power
|
||||
{
|
||||
var availiablePowerFraction = (float) remainingSupply / categoryPowerDemand;
|
||||
remainingSupply = 0;
|
||||
foreach (var consumer in _consumersByPriority[priority])
|
||||
{
|
||||
consumer.ReceivedPower = (int) (consumer.DrawRate * availiablePowerFraction); //give each consumer a fraction of what they requested (rounded down to nearest int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class NullPowerNet : IPowerNet
|
||||
{
|
||||
public void AddConsumer(PowerConsumerComponent consumer) { }
|
||||
public void AddSupplier(PowerSupplierComponent supplier) { }
|
||||
public void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate) { }
|
||||
public void RemoveConsumer(PowerConsumerComponent consumer) { }
|
||||
public void RemoveSupplier(PowerSupplierComponent supplier) { }
|
||||
public void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate) { }
|
||||
public void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority) { }
|
||||
public void UpdateConsumerReceivedPower() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -12,29 +13,19 @@ namespace Content.Server.NodeContainer.Nodes
|
||||
[DataDefinition]
|
||||
public class AdjacentNode : Node
|
||||
{
|
||||
protected override IEnumerable<Node> GetReachableNodes()
|
||||
public override IEnumerable<Node> GetReachableNodes()
|
||||
{
|
||||
if (!Owner.Transform.Anchored)
|
||||
yield break;
|
||||
|
||||
var compMgr = IoCManager.Resolve<IComponentManager>();
|
||||
var grid = IoCManager.Resolve<IMapManager>().GetGrid(Owner.Transform.GridID);
|
||||
var coords = Owner.Transform.Coordinates;
|
||||
foreach (var cell in grid.GetCardinalNeighborCells(coords))
|
||||
var gridIndex = grid.TileIndicesFor(Owner.Transform.Coordinates);
|
||||
|
||||
foreach (var (_, node) in NodeHelpers.GetCardinalNeighborNodes(compMgr, grid, gridIndex))
|
||||
{
|
||||
foreach (var entity in grid.GetLocal(Owner.EntityManager.GetEntity(cell).Transform.Coordinates))
|
||||
{
|
||||
if (!Owner.EntityManager.GetEntity(entity).TryGetComponent<NodeContainerComponent>(out var container))
|
||||
continue;
|
||||
|
||||
foreach (var node in container.Nodes.Values)
|
||||
{
|
||||
if (node != null && node != this)
|
||||
{
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (node != this)
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -26,20 +23,14 @@ namespace Content.Server.NodeContainer.Nodes
|
||||
[DataField("nodeGroupID")]
|
||||
public NodeGroupID NodeGroupID { get; private set; } = NodeGroupID.Default;
|
||||
|
||||
[ViewVariables]
|
||||
public INodeGroup NodeGroup { get => _nodeGroup; set => SetNodeGroup(value); }
|
||||
private INodeGroup _nodeGroup = BaseNodeGroup.NullGroup;
|
||||
[ViewVariables] public INodeGroup? NodeGroup;
|
||||
|
||||
[ViewVariables]
|
||||
public IEntity Owner { get; private set; } = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private bool _needsGroup = true;
|
||||
[ViewVariables] public IEntity Owner { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// If this node should be considered for connection by other nodes.
|
||||
/// </summary>
|
||||
public bool Connectable => !_deleting && Anchored;
|
||||
public bool Connectable => !Deleting && Anchored;
|
||||
|
||||
protected bool Anchored => !NeedAnchored || Owner.Transform.Anchored;
|
||||
|
||||
@@ -50,7 +41,15 @@ namespace Content.Server.NodeContainer.Nodes
|
||||
/// <summary>
|
||||
/// Prevents a node from being used by other nodes while midway through removal.
|
||||
/// </summary>
|
||||
private bool _deleting;
|
||||
public bool Deleting;
|
||||
|
||||
public readonly HashSet<Node> ReachableNodes = new();
|
||||
|
||||
internal int FloodGen;
|
||||
internal int UndirectGen;
|
||||
internal bool FlaggedForFlood;
|
||||
internal int NetId;
|
||||
public string Name = default!;
|
||||
|
||||
public virtual void Initialize(IEntity owner)
|
||||
{
|
||||
@@ -59,20 +58,23 @@ namespace Content.Server.NodeContainer.Nodes
|
||||
|
||||
public virtual void OnContainerStartup()
|
||||
{
|
||||
TryAssignGroupIfNeeded();
|
||||
CombineGroupWithReachable();
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueReflood(this);
|
||||
}
|
||||
|
||||
public void CreateSingleNetImmediate()
|
||||
{
|
||||
EntitySystem.Get<NodeGroupSystem>().CreateSingleNetImmediate(this);
|
||||
}
|
||||
|
||||
public void AnchorUpdate()
|
||||
{
|
||||
if (Anchored)
|
||||
{
|
||||
TryAssignGroupIfNeeded();
|
||||
CombineGroupWithReachable();
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueReflood(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveSelfFromGroup();
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueNodeRemove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,107 +82,21 @@ namespace Content.Server.NodeContainer.Nodes
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnPostRebuild()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void OnContainerShutdown()
|
||||
{
|
||||
_deleting = true;
|
||||
NodeGroup.RemoveNode(this);
|
||||
}
|
||||
|
||||
public bool TryAssignGroupIfNeeded()
|
||||
{
|
||||
if (!_needsGroup || !Connectable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
NodeGroup = GetReachableCompatibleGroups().FirstOrDefault() ?? MakeNewGroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SpreadGroup()
|
||||
{
|
||||
Debug.Assert(!_needsGroup);
|
||||
foreach (var node in GetReachableCompatibleNodes())
|
||||
{
|
||||
if (node._needsGroup)
|
||||
{
|
||||
node.NodeGroup = NodeGroup;
|
||||
node.SpreadGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearNodeGroup()
|
||||
{
|
||||
_nodeGroup = BaseNodeGroup.NullGroup;
|
||||
_needsGroup = true;
|
||||
}
|
||||
|
||||
protected void RefreshNodeGroup()
|
||||
{
|
||||
RemoveSelfFromGroup();
|
||||
TryAssignGroupIfNeeded();
|
||||
CombineGroupWithReachable();
|
||||
Deleting = true;
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueNodeRemove(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How this node will attempt to find other reachable <see cref="Node"/>s to group with.
|
||||
/// Returns a set of <see cref="Node"/>s to consider grouping with. Should not return this current <see cref="Node"/>.
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<Node> GetReachableNodes();
|
||||
|
||||
private IEnumerable<Node> GetReachableCompatibleNodes()
|
||||
{
|
||||
foreach (var node in GetReachableNodes())
|
||||
{
|
||||
if (node.NodeGroupID == NodeGroupID && node.Connectable)
|
||||
{
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<INodeGroup> GetReachableCompatibleGroups()
|
||||
{
|
||||
foreach (var node in GetReachableCompatibleNodes())
|
||||
{
|
||||
if (!node._needsGroup)
|
||||
{
|
||||
var group = node.NodeGroup;
|
||||
if (group != NodeGroup)
|
||||
{
|
||||
yield return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CombineGroupWithReachable()
|
||||
{
|
||||
if (_needsGroup || !Connectable)
|
||||
return;
|
||||
|
||||
foreach (var group in GetReachableCompatibleGroups())
|
||||
{
|
||||
NodeGroup.CombineGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetNodeGroup(INodeGroup newGroup)
|
||||
{
|
||||
_nodeGroup = newGroup;
|
||||
NodeGroup.AddNode(this);
|
||||
_needsGroup = false;
|
||||
}
|
||||
|
||||
private INodeGroup MakeNewGroup()
|
||||
{
|
||||
return IoCManager.Resolve<INodeGroupFactory>().MakeNodeGroup(this);
|
||||
}
|
||||
|
||||
private void RemoveSelfFromGroup()
|
||||
{
|
||||
NodeGroup.RemoveNode(this);
|
||||
ClearNodeGroup();
|
||||
}
|
||||
public abstract IEnumerable<Node> GetReachableNodes();
|
||||
}
|
||||
}
|
||||
|
||||
89
Content.Server/NodeContainer/Nodes/NodeHelpers.cs
Normal file
89
Content.Server/NodeContainer/Nodes/NodeHelpers.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.NodeContainer.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper utilities for implementing <see cref="Node"/>.
|
||||
/// </summary>
|
||||
public static class NodeHelpers
|
||||
{
|
||||
public static IEnumerable<Node> GetNodesInTile(IComponentManager compMgr, IMapGrid grid, Vector2i coords)
|
||||
{
|
||||
foreach (var entityUid in grid.GetAnchoredEntities(coords))
|
||||
{
|
||||
if (!compMgr.TryGetComponent(entityUid, out NodeContainerComponent? container))
|
||||
continue;
|
||||
|
||||
foreach (var node in container.Nodes.Values)
|
||||
{
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<(Direction dir, Node node)> GetCardinalNeighborNodes(
|
||||
IComponentManager compMgr,
|
||||
IMapGrid grid,
|
||||
Vector2i coords,
|
||||
bool includeSameTile = true)
|
||||
{
|
||||
foreach (var (dir, entityUid) in GetCardinalNeighborCells(grid, coords, includeSameTile))
|
||||
{
|
||||
if (!compMgr.TryGetComponent(entityUid, out NodeContainerComponent? container))
|
||||
continue;
|
||||
|
||||
foreach (var node in container.Nodes.Values)
|
||||
{
|
||||
yield return (dir, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "EnforceForeachStatementBraces")]
|
||||
public static IEnumerable<(Direction dir, EntityUid entity)> GetCardinalNeighborCells(
|
||||
IMapGrid grid,
|
||||
Vector2i coords,
|
||||
bool includeSameTile = true)
|
||||
{
|
||||
if (includeSameTile)
|
||||
{
|
||||
foreach (var uid in grid.GetAnchoredEntities(coords))
|
||||
yield return (Direction.Invalid, uid);
|
||||
}
|
||||
|
||||
foreach (var uid in grid.GetAnchoredEntities(coords + (0, 1)))
|
||||
yield return (Direction.North, uid);
|
||||
|
||||
foreach (var uid in grid.GetAnchoredEntities(coords + (0, -1)))
|
||||
yield return (Direction.South, uid);
|
||||
|
||||
foreach (var uid in grid.GetAnchoredEntities(coords + (1, 0)))
|
||||
yield return (Direction.East, uid);
|
||||
|
||||
foreach (var uid in grid.GetAnchoredEntities(coords + (-1, 0)))
|
||||
yield return (Direction.West, uid);
|
||||
}
|
||||
|
||||
public static Vector2i TileOffsetForDir(Direction dir)
|
||||
{
|
||||
return dir switch
|
||||
{
|
||||
Direction.Invalid => (0, 0),
|
||||
Direction.South => (0, -1),
|
||||
Direction.SouthEast => (1, -1),
|
||||
Direction.East => (1, 0),
|
||||
Direction.NorthEast => (1, 1),
|
||||
Direction.North => (0, 1),
|
||||
Direction.NorthWest => (-1, 1),
|
||||
Direction.West => (-1, 0),
|
||||
Direction.SouthWest => (-1, -1),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(dir), dir, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,8 @@ using System.Collections.Generic;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
@@ -13,9 +12,10 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
namespace Content.Server.NodeContainer.Nodes
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects with other <see cref="PipeNode"/>s whose <see cref="PipeDirection"/>
|
||||
@@ -63,21 +63,23 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
set
|
||||
{
|
||||
_connectionsEnabled = value;
|
||||
RefreshNodeGroup();
|
||||
|
||||
if (NodeGroup != null)
|
||||
EntitySystem.Get<NodeGroupSystem>().QueueRemakeGroup((BaseNodeGroup) NodeGroup);
|
||||
}
|
||||
}
|
||||
|
||||
[DataField("connectionsEnabled")]
|
||||
private bool _connectionsEnabled = true;
|
||||
|
||||
[DataField("rotationsEnabled")]
|
||||
public bool RotationsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IPipeNet"/> this pipe is a part of. Set to <see cref="PipeNet.NullNet"/> when not in an <see cref="IPipeNet"/>.
|
||||
/// The <see cref="IPipeNet"/> this pipe is a part of.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private IPipeNet _pipeNet = PipeNet.NullNet;
|
||||
|
||||
[DataField("connectionsEnabled")]
|
||||
private bool _connectionsEnabled = true;
|
||||
private IPipeNet? PipeNet => (IPipeNet?) NodeGroup;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to ignore the pipenet and return the environment's air.
|
||||
@@ -92,8 +94,12 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
[ViewVariables]
|
||||
public GasMixture Air
|
||||
{
|
||||
get => !EnvironmentalAir ? _pipeNet.Air : Owner.Transform.Coordinates.GetTileAir() ?? GasMixture.SpaceGas;
|
||||
set => _pipeNet.Air = value;
|
||||
get => (!EnvironmentalAir ? PipeNet?.Air : Owner.Transform.Coordinates.GetTileAir()) ?? GasMixture.SpaceGas;
|
||||
set
|
||||
{
|
||||
DebugTools.Assert(PipeNet != null);
|
||||
PipeNet!.Air = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void AssumeAir(GasMixture giver)
|
||||
@@ -105,7 +111,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
return;
|
||||
}
|
||||
|
||||
EntitySystem.Get<AtmosphereSystem>().Merge(_pipeNet.Air, giver);
|
||||
EntitySystem.Get<AtmosphereSystem>().Merge(PipeNet!.Air, giver);
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
@@ -128,13 +134,6 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
|
||||
public void JoinPipeNet(IPipeNet pipeNet)
|
||||
{
|
||||
_pipeNet = pipeNet;
|
||||
OnConnectedDirectionsNeedsUpdating();
|
||||
}
|
||||
|
||||
public void ClearPipeNet()
|
||||
{
|
||||
_pipeNet = PipeNet.NullNet;
|
||||
OnConnectedDirectionsNeedsUpdating();
|
||||
}
|
||||
|
||||
@@ -146,12 +145,11 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||
if (!RotationsEnabled) return;
|
||||
var diff = ev.NewRotation - ev.OldRotation;
|
||||
PipeDirection = PipeDirection.RotatePipeDirection(diff);
|
||||
RefreshNodeGroup();
|
||||
OnConnectedDirectionsNeedsUpdating();
|
||||
UpdateAppearance();
|
||||
}
|
||||
|
||||
protected override IEnumerable<Node> GetReachableNodes()
|
||||
public override IEnumerable<Node> GetReachableNodes()
|
||||
{
|
||||
for (var i = 0; i < PipeDirectionHelpers.AllPipeDirections; i++)
|
||||
{
|
||||
|
||||
@@ -6,9 +6,10 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using Content.Server.Notification;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Server.VendingMachines;
|
||||
using Content.Server.Wires.Components;
|
||||
using Content.Server.WireHacking;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
@@ -47,7 +48,7 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
/// <summary>
|
||||
/// Power receiver for the control console itself.
|
||||
/// </summary>
|
||||
[ViewVariables] private PowerReceiverComponent _powerReceiverComponent = default!;
|
||||
[ViewVariables] private ApcPowerReceiverComponent _apcPowerReceiverComponent = default!;
|
||||
|
||||
[ViewVariables] private ParticleAcceleratorFuelChamberComponent? _partFuelChamber;
|
||||
[ViewVariables] private ParticleAcceleratorEndCapComponent? _partEndCap;
|
||||
@@ -88,7 +89,7 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("powerDrawBase")] private int _powerDrawBase = 500;
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("powerDrawMult")] private int _powerDrawMult = 1500;
|
||||
|
||||
[ViewVariables] private bool ConsolePowered => _powerReceiverComponent?.Powered ?? true;
|
||||
[ViewVariables] private bool ConsolePowered => _apcPowerReceiverComponent?.Powered ?? true;
|
||||
|
||||
public ParticleAcceleratorControlBoxComponent()
|
||||
{
|
||||
@@ -107,9 +108,9 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||
}
|
||||
|
||||
Owner.EnsureComponent(out _powerReceiverComponent);
|
||||
Owner.EnsureComponent(out _apcPowerReceiverComponent);
|
||||
|
||||
_powerReceiverComponent!.Load = 250;
|
||||
_apcPowerReceiverComponent!.Load = 250;
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
@@ -189,8 +190,8 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
|
||||
public void UpdateUI()
|
||||
{
|
||||
var draw = 0;
|
||||
var receive = 0;
|
||||
var draw = 0f;
|
||||
var receive = 0f;
|
||||
|
||||
if (_isEnabled)
|
||||
{
|
||||
@@ -202,8 +203,8 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
_isAssembled,
|
||||
_isEnabled,
|
||||
_selectedStrength,
|
||||
draw,
|
||||
receive,
|
||||
(int) draw,
|
||||
(int) receive,
|
||||
_partEmitterLeft != null,
|
||||
_partEmitterCenter != null,
|
||||
_partEmitterRight != null,
|
||||
@@ -577,7 +578,7 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(ParticleAcceleratorVisuals.VisualState,
|
||||
_powerReceiverComponent!.Powered
|
||||
_apcPowerReceiverComponent!.Powered
|
||||
? (ParticleAcceleratorVisualState) _selectedStrength
|
||||
: ParticleAcceleratorVisualState.Unpowered);
|
||||
}
|
||||
@@ -645,7 +646,7 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
} * _powerDrawMult + _powerDrawBase;
|
||||
}
|
||||
|
||||
public void PowerBoxReceivedChanged(object? sender, ReceivedPowerChangedEventArgs eventArgs)
|
||||
public void PowerBoxReceivedChanged(PowerConsumerReceivedChanged eventArgs)
|
||||
{
|
||||
DebugTools.Assert(_isAssembled);
|
||||
|
||||
|
||||
@@ -17,12 +17,6 @@ namespace Content.Server.ParticleAccelerator.Components
|
||||
base.Initialize();
|
||||
|
||||
PowerConsumerComponent = Owner.EnsureComponentWarn<PowerConsumerComponent>();
|
||||
PowerConsumerComponent.OnReceivedPowerChanged += PowerReceivedChanged;
|
||||
}
|
||||
|
||||
private void PowerReceivedChanged(object? sender, ReceivedPowerChangedEventArgs e)
|
||||
{
|
||||
Master?.PowerBoxReceivedChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Server.ParticleAccelerator.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ParticleAcceleratorPartSystem : EntitySystem
|
||||
@@ -0,0 +1,27 @@
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ParticleAcceleratorPowerBoxSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ParticleAcceleratorPowerBoxComponent, PowerConsumerReceivedChanged>(
|
||||
PowerBoxReceivedChanged);
|
||||
}
|
||||
|
||||
private static void PowerBoxReceivedChanged(
|
||||
EntityUid uid,
|
||||
ParticleAcceleratorPowerBoxComponent component,
|
||||
PowerConsumerReceivedChanged args)
|
||||
{
|
||||
component.Master!.PowerBoxReceivedChanged(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Content.Server/Power/Commands/PowerStatCommand.cs
Normal file
26
Content.Server/Power/Commands/PowerStatCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Power.Commands
|
||||
{
|
||||
[AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class PowerStatCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "powerstat";
|
||||
public string Description => "Shows statistics for pow3r";
|
||||
public string Help => "Usage: powerstat";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var stats = EntitySystem.Get<PowerNetSystem>().GetStatistics();
|
||||
|
||||
shell.WriteLine($"networks: {stats.CountNetworks}");
|
||||
shell.WriteLine($"loads: {stats.CountLoads}");
|
||||
shell.WriteLine($"supplies: {stats.CountSupplies}");
|
||||
shell.WriteLine($"batteries: {stats.CountBatteries}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.Access.Components;
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.APC;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.APC.Components
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
@@ -57,7 +56,6 @@ namespace Content.Server.APC.Components
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Owner.EnsureComponent<PowerConsumerComponent>();
|
||||
Owner.EnsureComponentWarn<ServerUserInterfaceComponent>();
|
||||
Owner.EnsureComponentWarn<AccessReader>();
|
||||
|
||||
@@ -89,6 +87,8 @@ namespace Content.Server.APC.Components
|
||||
if (_accessReader == null || _accessReader.IsAllowed(user))
|
||||
{
|
||||
MainBreakerEnabled = !MainBreakerEnabled;
|
||||
Owner.GetComponent<PowerNetworkBatteryComponent>().CanDischarge = MainBreakerEnabled;
|
||||
|
||||
_uiDirty = true;
|
||||
SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f));
|
||||
}
|
||||
@@ -153,44 +153,31 @@ namespace Content.Server.APC.Components
|
||||
return ApcChargeState.Full;
|
||||
}
|
||||
|
||||
if (!Owner.TryGetComponent(out PowerConsumerComponent? consumer))
|
||||
{
|
||||
return ApcChargeState.Full;
|
||||
}
|
||||
var netBattery = Owner.GetComponent<PowerNetworkBatteryComponent>();
|
||||
var delta = netBattery.CurrentSupply - netBattery.CurrentReceiving;
|
||||
|
||||
if (consumer.DrawRate == consumer.ReceivedPower)
|
||||
{
|
||||
return ApcChargeState.Charging;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApcChargeState.Lack;
|
||||
}
|
||||
return delta < 0 ? ApcChargeState.Charging : ApcChargeState.Lack;
|
||||
}
|
||||
|
||||
private ApcExternalPowerState CalcExtPowerState()
|
||||
{
|
||||
if (!Owner.TryGetComponent(out BatteryStorageComponent? batteryStorage))
|
||||
var bat = Battery;
|
||||
if (bat == null)
|
||||
return ApcExternalPowerState.None;
|
||||
|
||||
var netBat = Owner.GetComponent<PowerNetworkBatteryComponent>();
|
||||
if (netBat.CurrentReceiving == 0 && netBat.LoadingNetworkDemand != 0)
|
||||
{
|
||||
return ApcExternalPowerState.None;
|
||||
}
|
||||
var consumer = batteryStorage.Consumer;
|
||||
|
||||
if (consumer == null)
|
||||
return ApcExternalPowerState.None;
|
||||
|
||||
if (consumer.ReceivedPower == 0 && consumer.DrawRate != 0)
|
||||
{
|
||||
return ApcExternalPowerState.None;
|
||||
}
|
||||
else if (consumer.ReceivedPower < consumer.DrawRate)
|
||||
var delta = netBat.CurrentReceiving - netBat.LoadingNetworkDemand;
|
||||
if (!MathHelper.CloseTo(delta, 0, 0.1f) && delta < 0)
|
||||
{
|
||||
return ApcExternalPowerState.Low;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApcExternalPowerState.Good;
|
||||
}
|
||||
|
||||
return ApcExternalPowerState.Good;
|
||||
}
|
||||
|
||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||
121
Content.Server/Power/Components/ApcPowerProviderComponent.cs
Normal file
121
Content.Server/Power/Components/ApcPowerProviderComponent.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ApcPowerProviderComponent : BaseApcNetComponent
|
||||
{
|
||||
public override string Name => "PowerProvider";
|
||||
|
||||
public IEntity ProviderOwner => Owner;
|
||||
|
||||
/// <summary>
|
||||
/// The max distance this can transmit power to <see cref="ApcPowerReceiverComponent"/>s from.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PowerTransferRange { get => _powerTransferRange; set => SetPowerTransferRange(value); }
|
||||
[DataField("powerTransferRange")]
|
||||
private int _powerTransferRange = 3;
|
||||
|
||||
[ViewVariables] public List<ApcPowerReceiverComponent> LinkedReceivers { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="ApcPowerReceiverComponent"/>s should consider connecting to this.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Connectable { get; private set; } = true;
|
||||
|
||||
public void AddReceiver(ApcPowerReceiverComponent receiver)
|
||||
{
|
||||
LinkedReceivers.Add(receiver);
|
||||
receiver.NetworkLoad.LinkedNetwork = default;
|
||||
|
||||
Net?.QueueNetworkReconnect();
|
||||
}
|
||||
|
||||
public void RemoveReceiver(ApcPowerReceiverComponent receiver)
|
||||
{
|
||||
LinkedReceivers.Remove(receiver);
|
||||
receiver.NetworkLoad.LinkedNetwork = default;
|
||||
|
||||
Net?.QueueNetworkReconnect();
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
foreach (var receiver in FindAvailableReceivers())
|
||||
{
|
||||
receiver.Provider = this;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
Connectable = false;
|
||||
var receivers = LinkedReceivers.ToArray();
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.Provider = null;
|
||||
}
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.TryFindAndSetProvider();
|
||||
}
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
private IEnumerable<ApcPowerReceiverComponent> FindAvailableReceivers()
|
||||
{
|
||||
var nearbyEntities = IoCManager.Resolve<IEntityLookup>()
|
||||
.GetEntitiesInRange(Owner, PowerTransferRange);
|
||||
|
||||
foreach (var entity in nearbyEntities)
|
||||
{
|
||||
if (entity.TryGetComponent<ApcPowerReceiverComponent>(out var receiver) &&
|
||||
receiver.Connectable &&
|
||||
receiver.NeedsProvider &&
|
||||
receiver.Owner.Transform.Coordinates.TryDistance(Owner.EntityManager, Owner.Transform.Coordinates, out var distance) &&
|
||||
distance < Math.Min(PowerTransferRange, receiver.PowerReceptionRange))
|
||||
{
|
||||
yield return receiver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AddSelfToNet(IApcNet apcNet)
|
||||
{
|
||||
apcNet.AddPowerProvider(this);
|
||||
}
|
||||
|
||||
protected override void RemoveSelfFromNet(IApcNet apcNet)
|
||||
{
|
||||
apcNet.RemovePowerProvider(this);
|
||||
}
|
||||
|
||||
private void SetPowerTransferRange(int newPowerTransferRange)
|
||||
{
|
||||
var receivers = LinkedReceivers.ToArray();
|
||||
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.Provider = null;
|
||||
}
|
||||
|
||||
_powerTransferRange = newPowerTransferRange;
|
||||
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.TryFindAndSetProvider();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.APC;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Content.Server.Power.Pow3r;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -15,26 +18,21 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to link with a nearby <see cref="IPowerProvider"/>s so that it can receive power from a <see cref="IApcNet"/>.
|
||||
/// Attempts to link with a nearby <see cref="ApcPowerProviderComponent"/>s
|
||||
/// so that it can receive power from a <see cref="IApcNet"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class PowerReceiverComponent : Component, IExamine
|
||||
public class ApcPowerReceiverComponent : Component, IExamine
|
||||
{
|
||||
[ViewVariables] [ComponentDependency] private readonly IPhysBody? _physicsComponent = null;
|
||||
|
||||
public override string Name => "PowerReceiver";
|
||||
public override string Name => "ApcPowerReceiver";
|
||||
|
||||
[ViewVariables]
|
||||
public bool Powered => (HasApcPower || !NeedsPower) && !PowerDisabled;
|
||||
public bool Powered => (MathHelper.CloseTo(NetworkLoad.ReceivingPower, Load) || !NeedsPower) && !PowerDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// If this is being powered by an Apc.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool HasApcPower { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The max distance from a <see cref="PowerProviderComponent"/> that this can receive power from.
|
||||
/// The max distance from a <see cref="ApcPowerProviderComponent"/> that this can receive power from.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PowerReceptionRange { get => _powerReceptionRange; set => SetPowerReceptionRange(value); }
|
||||
@@ -42,32 +40,53 @@ namespace Content.Server.Power.Components
|
||||
private int _powerReceptionRange = 3;
|
||||
|
||||
[ViewVariables]
|
||||
public IPowerProvider Provider { get => _provider; set => SetProvider(value); }
|
||||
private IPowerProvider _provider = PowerProviderComponent.NullProvider;
|
||||
public ApcPowerProviderComponent? Provider
|
||||
{
|
||||
get => _provider;
|
||||
set
|
||||
{
|
||||
// Will get updated before power networks process.
|
||||
NetworkLoad.LinkedNetwork = default;
|
||||
_provider?.RemoveReceiver(this);
|
||||
_provider = value;
|
||||
value?.AddReceiver(this);
|
||||
ApcPowerChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private ApcPowerProviderComponent? _provider;
|
||||
|
||||
/// <summary>
|
||||
/// If this should be considered for connection by <see cref="PowerProviderComponent"/>s.
|
||||
/// If this should be considered for connection by <see cref="ApcPowerProviderComponent"/>s.
|
||||
/// </summary>
|
||||
public bool Connectable => Anchored;
|
||||
|
||||
private bool Anchored => _physicsComponent == null || _physicsComponent.BodyType == BodyType.Static;
|
||||
|
||||
[ViewVariables]
|
||||
public bool NeedsProvider { get; private set; } = true;
|
||||
[ViewVariables] public bool NeedsProvider => Provider == null;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of charge this needs from an APC per second to function.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int Load { get => _load; set => SetLoad(value); }
|
||||
[DataField("powerLoad")]
|
||||
private int _load = 5;
|
||||
public float Load { get => NetworkLoad.DesiredPower; set => NetworkLoad.DesiredPower = value; }
|
||||
|
||||
/// <summary>
|
||||
/// When false, causes this to appear powered even if not receiving power from an Apc.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool NeedsPower { get => _needsPower; set => SetNeedsPower(value); }
|
||||
public bool NeedsPower
|
||||
{
|
||||
get => _needsPower;
|
||||
set
|
||||
{
|
||||
_needsPower = value;
|
||||
// Reset this so next tick will do a power update.
|
||||
LastPowerReceived = float.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
[DataField("needsPower")]
|
||||
private bool _needsPower = true;
|
||||
|
||||
@@ -75,9 +94,16 @@ namespace Content.Server.Power.Components
|
||||
/// When true, causes this to never appear powered.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool PowerDisabled { get => _powerDisabled; set => SetPowerDisabled(value); }
|
||||
[DataField("powerDisabled")]
|
||||
private bool _powerDisabled;
|
||||
public bool PowerDisabled { get => !NetworkLoad.Enabled; set => NetworkLoad.Enabled = !value; }
|
||||
|
||||
public float LastPowerReceived = float.NaN;
|
||||
|
||||
[ViewVariables]
|
||||
public PowerState.Load NetworkLoad { get; } = new PowerState.Load
|
||||
{
|
||||
DesiredPower = 5
|
||||
};
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
@@ -94,7 +120,8 @@ namespace Content.Server.Power.Components
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
_provider.RemoveReceiver(this);
|
||||
_provider?.RemoveReceiver(this);
|
||||
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
@@ -108,20 +135,17 @@ namespace Content.Server.Power.Components
|
||||
|
||||
public void ApcPowerChanged()
|
||||
{
|
||||
var oldPowered = Powered;
|
||||
HasApcPower = Provider.HasApcPower;
|
||||
if (Powered != oldPowered)
|
||||
OnNewPowerState();
|
||||
OnNewPowerState();
|
||||
}
|
||||
|
||||
private bool TryFindAvailableProvider(out IPowerProvider foundProvider)
|
||||
private bool TryFindAvailableProvider([NotNullWhen(true)] out ApcPowerProviderComponent? foundProvider)
|
||||
{
|
||||
var nearbyEntities = IoCManager.Resolve<IEntityLookup>()
|
||||
.GetEntitiesInRange(Owner, PowerReceptionRange);
|
||||
|
||||
foreach (var entity in nearbyEntities)
|
||||
{
|
||||
if (entity.TryGetComponent<PowerProviderComponent>(out var provider))
|
||||
if (entity.TryGetComponent<ApcPowerProviderComponent>(out var provider))
|
||||
{
|
||||
if (provider.Connectable)
|
||||
{
|
||||
@@ -136,60 +160,18 @@ namespace Content.Server.Power.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
foundProvider = default!;
|
||||
|
||||
foundProvider = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ClearProvider()
|
||||
{
|
||||
_provider.RemoveReceiver(this);
|
||||
_provider = PowerProviderComponent.NullProvider;
|
||||
NeedsProvider = true;
|
||||
ApcPowerChanged();
|
||||
}
|
||||
|
||||
private void SetProvider(IPowerProvider newProvider)
|
||||
{
|
||||
_provider.RemoveReceiver(this);
|
||||
_provider = newProvider;
|
||||
newProvider.AddReceiver(this);
|
||||
NeedsProvider = false;
|
||||
ApcPowerChanged();
|
||||
}
|
||||
|
||||
private void SetPowerReceptionRange(int newPowerReceptionRange)
|
||||
{
|
||||
ClearProvider();
|
||||
Provider = null;
|
||||
_powerReceptionRange = newPowerReceptionRange;
|
||||
TryFindAndSetProvider();
|
||||
}
|
||||
|
||||
private void SetLoad(int newLoad)
|
||||
{
|
||||
Provider.UpdateReceiverLoad(Load, newLoad);
|
||||
_load = newLoad;
|
||||
}
|
||||
|
||||
private void SetNeedsPower(bool newNeedsPower)
|
||||
{
|
||||
var oldPowered = Powered;
|
||||
_needsPower = newNeedsPower;
|
||||
if (oldPowered != Powered)
|
||||
{
|
||||
OnNewPowerState();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPowerDisabled(bool newPowerDisabled)
|
||||
{
|
||||
var oldPowered = Powered;
|
||||
_powerDisabled = newPowerDisabled;
|
||||
if (oldPowered != Powered)
|
||||
{
|
||||
OnNewPowerState();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewPowerState()
|
||||
{
|
||||
SendMessage(new PowerChangedMessage(Powered));
|
||||
@@ -211,7 +193,7 @@ namespace Content.Server.Power.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearProvider();
|
||||
Provider = null;
|
||||
}
|
||||
}
|
||||
|
||||
9
Content.Server/Power/Components/BaseApcNetComponent.cs
Normal file
9
Content.Server/Power/Components/BaseApcNetComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
#nullable enable
|
||||
using Content.Server.Power.NodeGroups;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
public abstract class BaseApcNetComponent : BaseNetConnectorComponent<IApcNet>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Items;
|
||||
using Content.Server.Weapon.Ranged.Barrels.Components;
|
||||
@@ -45,7 +44,7 @@ namespace Content.Server.Power.Components
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Owner.EnsureComponent<PowerReceiverComponent>();
|
||||
Owner.EnsureComponent<ApcPowerReceiverComponent>();
|
||||
_container = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-powerCellContainer");
|
||||
// Default state in the visualizer is OFF, so when this gets powered on during initialization it will generally show empty
|
||||
}
|
||||
@@ -191,7 +190,7 @@ namespace Content.Server.Power.Components
|
||||
|
||||
private CellChargerStatus GetStatus()
|
||||
{
|
||||
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) &&
|
||||
if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
|
||||
!receiver.Powered)
|
||||
{
|
||||
return CellChargerStatus.Off;
|
||||
@@ -234,7 +233,7 @@ namespace Content.Server.Power.Components
|
||||
// Not called UpdateAppearance just because it messes with the load
|
||||
var status = GetStatus();
|
||||
if (_status == status ||
|
||||
!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||
!Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -279,7 +278,7 @@ namespace Content.Server.Power.Components
|
||||
|
||||
private void TransferPower(float frameTime)
|
||||
{
|
||||
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) &&
|
||||
if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
|
||||
!receiver.Powered)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -17,23 +17,18 @@ namespace Content.Server.Power.Components
|
||||
private Voltage _voltage = Voltage.High;
|
||||
|
||||
[ViewVariables]
|
||||
public TNetType Net { get => _net; set => SetNet(value); }
|
||||
private TNetType _net = default!; //set in OnAdd()
|
||||
|
||||
protected abstract TNetType NullNet { get; }
|
||||
public TNetType? Net { get => _net; set => SetNet(value); }
|
||||
private TNetType? _net;
|
||||
|
||||
[ViewVariables]
|
||||
private bool _needsNet = true;
|
||||
private bool _needsNet => _net != null;
|
||||
|
||||
protected override void OnAdd()
|
||||
{
|
||||
base.OnAdd();
|
||||
_net = NullNet;
|
||||
}
|
||||
[DataField("node")] [ViewVariables] public string? NodeId;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
if (_needsNet)
|
||||
{
|
||||
TryFindAndSetNet();
|
||||
@@ -56,9 +51,8 @@ namespace Content.Server.Power.Components
|
||||
|
||||
public void ClearNet()
|
||||
{
|
||||
RemoveSelfFromNet(_net);
|
||||
_net = NullNet;
|
||||
_needsNet = true;
|
||||
if (_net != null)
|
||||
RemoveSelfFromNet(_net);
|
||||
}
|
||||
|
||||
protected abstract void AddSelfToNet(TNetType net);
|
||||
@@ -70,7 +64,7 @@ namespace Content.Server.Power.Components
|
||||
if (Owner.TryGetComponent<NodeContainerComponent>(out var container))
|
||||
{
|
||||
var compatibleNet = container.Nodes.Values
|
||||
.Where(node => node.NodeGroupID == (NodeGroupID) Voltage)
|
||||
.Where(node => (NodeId == null || NodeId == node.Name) && node.NodeGroupID == (NodeGroupID) Voltage)
|
||||
.Select(node => node.NodeGroup)
|
||||
.OfType<TNetType>()
|
||||
.FirstOrDefault();
|
||||
@@ -85,12 +79,15 @@ namespace Content.Server.Power.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetNet(TNetType newNet)
|
||||
private void SetNet(TNetType? newNet)
|
||||
{
|
||||
RemoveSelfFromNet(_net);
|
||||
AddSelfToNet(newNet);
|
||||
if (_net != null)
|
||||
RemoveSelfFromNet(_net);
|
||||
|
||||
if (newNet != null)
|
||||
AddSelfToNet(newNet);
|
||||
|
||||
_net = newNet;
|
||||
_needsNet = false;
|
||||
}
|
||||
|
||||
private void SetVoltage(Voltage newVoltage)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#nullable enable
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
public abstract class BasePowerNetComponent : BaseNetConnectorComponent<IPowerNet>
|
||||
{
|
||||
protected override IPowerNet NullNet => PowerNetNodeGroup.NullNet;
|
||||
}
|
||||
}
|
||||
|
||||
24
Content.Server/Power/Components/BatteryChargerComponent.cs
Normal file
24
Content.Server/Power/Components/BatteryChargerComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Connects the loading side of a <see cref="BatteryComponent"/> to a non-APC power network.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class BatteryChargerComponent : BasePowerNetComponent
|
||||
{
|
||||
public override string Name => "BatteryCharger";
|
||||
|
||||
protected override void AddSelfToNet(IPowerNet net)
|
||||
{
|
||||
net.AddCharger(this);
|
||||
}
|
||||
|
||||
protected override void RemoveSelfFromNet(IPowerNet net)
|
||||
{
|
||||
net.RemoveCharger(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,11 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Battery.Components
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Battery node on the pow3r network. Needs other components to connect to actual networks.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class BatteryComponent : Component
|
||||
{
|
||||
@@ -15,9 +18,9 @@ namespace Content.Server.Battery.Components
|
||||
/// <summary>
|
||||
/// Maximum charge of the battery in joules (ie. watt seconds)
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)] public int MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
|
||||
[DataField("maxCharge")]
|
||||
private int _maxCharge = 1000;
|
||||
private float _maxCharge;
|
||||
|
||||
/// <summary>
|
||||
/// Current charge of the battery in joules (ie. watt seconds)
|
||||
@@ -25,7 +28,7 @@ namespace Content.Server.Battery.Components
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float CurrentCharge { get => _currentCharge; set => SetCurrentCharge(value); }
|
||||
[DataField("startingCharge")]
|
||||
private float _currentCharge = 500;
|
||||
private float _currentCharge;
|
||||
|
||||
/// <summary>
|
||||
/// True if the battery is fully charged.
|
||||
@@ -36,14 +39,6 @@ namespace Content.Server.Battery.Components
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("autoRechargeRate")] public float AutoRechargeRate { get; set; }
|
||||
|
||||
[ViewVariables] public BatteryState BatteryState { get; private set; }
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
UpdateStorageState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If sufficient charge is avaiable on the battery, use it. Otherwise, don't.
|
||||
/// </summary>
|
||||
@@ -83,34 +78,16 @@ namespace Content.Server.Battery.Components
|
||||
|
||||
protected virtual void OnChargeChanged() { }
|
||||
|
||||
private void UpdateStorageState()
|
||||
{
|
||||
if (IsFullyCharged)
|
||||
{
|
||||
BatteryState = BatteryState.Full;
|
||||
}
|
||||
else if (CurrentCharge == 0)
|
||||
{
|
||||
BatteryState = BatteryState.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
BatteryState = BatteryState.PartlyFull;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMaxCharge(int newMax)
|
||||
private void SetMaxCharge(float newMax)
|
||||
{
|
||||
_maxCharge = Math.Max(newMax, 0);
|
||||
_currentCharge = Math.Min(_currentCharge, MaxCharge);
|
||||
UpdateStorageState();
|
||||
OnChargeChanged();
|
||||
}
|
||||
|
||||
private void SetCurrentCharge(float newChargeAmount)
|
||||
{
|
||||
_currentCharge = MathHelper.Clamp(newChargeAmount, 0, MaxCharge);
|
||||
UpdateStorageState();
|
||||
OnChargeChanged();
|
||||
}
|
||||
|
||||
@@ -121,11 +98,4 @@ namespace Content.Server.Battery.Components
|
||||
CurrentCharge += AutoRechargeRate * frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
public enum BatteryState
|
||||
{
|
||||
Full,
|
||||
PartlyFull,
|
||||
Empty
|
||||
}
|
||||
}
|
||||
@@ -1,79 +1,21 @@
|
||||
#nullable enable
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses charge from a <see cref="BatteryComponent"/> to supply power via a <see cref="PowerSupplierComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class BatteryDischargerComponent : Component
|
||||
public class BatteryDischargerComponent : BasePowerNetComponent
|
||||
{
|
||||
public override string Name => "BatteryDischarger";
|
||||
|
||||
[ViewVariables]
|
||||
[ComponentDependency] private BatteryComponent? _battery = default!;
|
||||
|
||||
[ViewVariables]
|
||||
[ComponentDependency] private PowerSupplierComponent? _supplier = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int ActiveSupplyRate { get => _activeSupplyRate; set => SetActiveSupplyRate(value); }
|
||||
|
||||
[DataField("activeSupplyRate")]
|
||||
private int _activeSupplyRate = 50;
|
||||
|
||||
protected override void Initialize()
|
||||
protected override void AddSelfToNet(IPowerNet net)
|
||||
{
|
||||
base.Initialize();
|
||||
Owner.EnsureComponentWarn<PowerSupplierComponent>();
|
||||
UpdateSupplyRate();
|
||||
net.AddDischarger(this);
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
protected override void RemoveSelfFromNet(IPowerNet net)
|
||||
{
|
||||
if (_battery == null)
|
||||
return;
|
||||
|
||||
//Simplified implementation - if the battery is empty, and charge is being added to the battery
|
||||
//at a lower rate that this is using it, the charge is used without creating power supply.
|
||||
_battery.CurrentCharge -= ActiveSupplyRate * frameTime;
|
||||
UpdateSupplyRate();
|
||||
}
|
||||
|
||||
private void UpdateSupplyRate()
|
||||
{
|
||||
if (_battery == null)
|
||||
return;
|
||||
|
||||
if (_battery.BatteryState == BatteryState.Empty)
|
||||
{
|
||||
SetSupplierSupplyRate(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSupplierSupplyRate(ActiveSupplyRate);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSupplierSupplyRate(int newSupplierSupplyRate)
|
||||
{
|
||||
if (_supplier == null)
|
||||
return;
|
||||
|
||||
if (_supplier.SupplyRate != newSupplierSupplyRate)
|
||||
{
|
||||
_supplier.SupplyRate = newSupplierSupplyRate;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetActiveSupplyRate(int newEnabledSupplyRate)
|
||||
{
|
||||
_activeSupplyRate = newEnabledSupplyRate;
|
||||
UpdateSupplyRate();
|
||||
net.RemoveDischarger(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Server.Battery.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Takes power via a <see cref="PowerConsumerComponent"/> to charge a <see cref="BatteryComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class BatteryStorageComponent : Component
|
||||
{
|
||||
public override string Name => "BatteryStorage";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int ActiveDrawRate { get => _activeDrawRate; set => SetActiveDrawRate(value); }
|
||||
[DataField("activeDrawRate")]
|
||||
private int _activeDrawRate = 100;
|
||||
|
||||
[ViewVariables]
|
||||
[ComponentDependency] private BatteryComponent? _battery = default!;
|
||||
|
||||
[ViewVariables]
|
||||
public PowerConsumerComponent? Consumer => _consumer;
|
||||
|
||||
[ComponentDependency] private PowerConsumerComponent? _consumer = default!;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
Owner.EnsureComponentWarn<PowerConsumerComponent>();
|
||||
UpdateDrawRate();
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
if (_consumer == null || _battery == null)
|
||||
return;
|
||||
|
||||
//Simplified implementation - If a frame adds more power to a partially full battery than it can hold, the power is lost.
|
||||
_battery.CurrentCharge += _consumer.ReceivedPower * frameTime;
|
||||
UpdateDrawRate();
|
||||
}
|
||||
|
||||
private void UpdateDrawRate()
|
||||
{
|
||||
if (_battery == null)
|
||||
return;
|
||||
|
||||
if (_battery.BatteryState == BatteryState.Full)
|
||||
{
|
||||
SetConsumerDraw(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetConsumerDraw(ActiveDrawRate);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConsumerDraw(int newConsumerDrawRate)
|
||||
{
|
||||
if (_consumer == null)
|
||||
return;
|
||||
|
||||
if (_consumer.DrawRate != newConsumerDrawRate)
|
||||
{
|
||||
_consumer.DrawRate = newConsumerDrawRate;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetActiveDrawRate(int newEnabledDrawRate)
|
||||
{
|
||||
_activeDrawRate = newEnabledDrawRate;
|
||||
UpdateDrawRate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,45 +3,44 @@ using System.Threading.Tasks;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Tools.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Tool;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Wires.Components
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the attached entity to be destroyed by a cutting tool, dropping a piece of wire.
|
||||
/// Allows the attached entity to be destroyed by a cutting tool, dropping a piece of cable.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class WireComponent : Component, IInteractUsing
|
||||
public class CableComponent : Component, IInteractUsing
|
||||
{
|
||||
public override string Name => "Wire";
|
||||
public override string Name => "Cable";
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("wireDroppedOnCutPrototype")]
|
||||
private string? _wireDroppedOnCutPrototype = "HVWireStack1";
|
||||
[DataField("cableDroppedOnCutPrototype")]
|
||||
private string? _cableDroppedOnCutPrototype = "CableHVStack1";
|
||||
|
||||
/// <summary>
|
||||
/// Checked by <see cref="WirePlacerComponent"/> to determine if there is
|
||||
/// already a wire of a type on a tile.
|
||||
/// Checked by <see cref="CablePlacerComponent"/> to determine if there is
|
||||
/// already a cable of a type on a tile.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public WireType WireType => _wireType;
|
||||
[DataField("wireType")]
|
||||
private WireType _wireType = WireType.HighVoltage;
|
||||
public CableType CableType => _cableType;
|
||||
[DataField("cableType")]
|
||||
private CableType _cableType = CableType.HighVoltage;
|
||||
|
||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
||||
{
|
||||
if (_wireDroppedOnCutPrototype == null)
|
||||
if (_cableDroppedOnCutPrototype == null)
|
||||
return false;
|
||||
|
||||
if (!eventArgs.Using.TryGetComponent<ToolComponent>(out var tool)) return false;
|
||||
if (!await tool.UseTool(eventArgs.User, Owner, 0.25f, ToolQuality.Cutting)) return false;
|
||||
|
||||
Owner.Delete();
|
||||
var droppedEnt = Owner.EntityManager.SpawnEntity(_wireDroppedOnCutPrototype, eventArgs.ClickLocation);
|
||||
var droppedEnt = Owner.EntityManager.SpawnEntity(_cableDroppedOnCutPrototype, eventArgs.ClickLocation);
|
||||
|
||||
// TODO: Literally just use a prototype that has a single thing in the stack, it's not that complicated...
|
||||
if (droppedEnt.TryGetComponent<StackComponent>(out var stack))
|
||||
@@ -51,7 +50,7 @@ namespace Content.Server.Wires.Components
|
||||
}
|
||||
}
|
||||
|
||||
public enum WireType
|
||||
public enum CableType
|
||||
{
|
||||
HighVoltage,
|
||||
MediumVoltage,
|
||||
@@ -9,28 +9,28 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Wires.Components
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
internal class WirePlacerComponent : Component, IAfterInteract
|
||||
internal class CablePlacerComponent : Component, IAfterInteract
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "WirePlacer";
|
||||
public override string Name => "CablePlacer";
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("wirePrototypeID")]
|
||||
private string? _wirePrototypeID = "HVWire";
|
||||
[DataField("cablePrototypeID")]
|
||||
private string? _cablePrototypeID = "CableHV";
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("blockingWireType")]
|
||||
private WireType _blockingWireType = WireType.HighVoltage;
|
||||
private CableType _blockingCableType = CableType.HighVoltage;
|
||||
|
||||
/// <inheritdoc />
|
||||
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
||||
{
|
||||
if (_wirePrototypeID == null)
|
||||
if (_cablePrototypeID == null)
|
||||
return true;
|
||||
if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
|
||||
return true;
|
||||
@@ -41,7 +41,7 @@ namespace Content.Server.Wires.Components
|
||||
return true;
|
||||
foreach (var anchored in grid.GetAnchoredEntities(snapPos))
|
||||
{
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent<WireComponent>(anchored, out var wire) && wire.WireType == _blockingWireType)
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent<CableComponent>(anchored, out var wire) && wire.CableType == _blockingCableType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ namespace Content.Server.Wires.Components
|
||||
&& !EntitySystem.Get<StackSystem>().Use(Owner.Uid, stack, 1))
|
||||
return true;
|
||||
|
||||
Owner.EntityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos));
|
||||
Owner.EntityManager.SpawnEntity(_cablePrototypeID, grid.GridTileToLocal(snapPos));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
16
Content.Server/Power/Components/CableVisComponent.cs
Normal file
16
Content.Server/Power/Components/CableVisComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class CableVisComponent : Component
|
||||
{
|
||||
public override string Name => "CableVis";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("node")]
|
||||
public string? Node;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.Localization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Battery.Components
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ExaminableBatteryComponent : Component, IExamine
|
||||
@@ -1,39 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a set of <see cref="IPowerNet"/>s that need to be updated with <see cref="IPowerNet.UpdateConsumerReceivedPower"/>.
|
||||
/// Defers updating to reduce recalculations when a group is altered multiple times in a frame.
|
||||
/// </summary>
|
||||
public interface IPowerNetManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Queue up an <see cref="IPowerNet"/> to be updated.
|
||||
/// </summary>
|
||||
void AddDirtyPowerNet(IPowerNet powerNet);
|
||||
|
||||
void Update(float frameTime);
|
||||
}
|
||||
|
||||
public class PowerNetManager : IPowerNetManager
|
||||
{
|
||||
private readonly HashSet<IPowerNet> _dirtyPowerNets = new();
|
||||
|
||||
public void AddDirtyPowerNet(IPowerNet powerNet)
|
||||
{
|
||||
_dirtyPowerNets.Add(powerNet);
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
foreach (var powerNet in _dirtyPowerNets)
|
||||
{
|
||||
powerNet.UpdateConsumerReceivedPower();
|
||||
}
|
||||
_dirtyPowerNets.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Content.Server.Power.Pow3r;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws power directly from an MV or HV wire it is on top of.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class PowerConsumerComponent : BasePowerNetComponent
|
||||
{
|
||||
@@ -16,28 +18,19 @@ namespace Content.Server.Power.Components
|
||||
/// <summary>
|
||||
/// How much power this needs to be fully powered.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int DrawRate { get => _drawRate; set => SetDrawRate(value); }
|
||||
[DataField("drawRate")]
|
||||
private int _drawRate;
|
||||
|
||||
/// <summary>
|
||||
/// Determines which <see cref="PowerConsumerComponent"/>s receive power when there is not enough
|
||||
/// power for each.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public Priority Priority { get => _priority; set => SetPriority(value); }
|
||||
[DataField("priority")]
|
||||
private Priority _priority = Priority.First;
|
||||
public float DrawRate { get => NetworkLoad.DesiredPower; set => NetworkLoad.DesiredPower = value; }
|
||||
|
||||
/// <summary>
|
||||
/// How much power this is currently receiving from <see cref="PowerSupplierComponent"/>s.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public int ReceivedPower { get => _receivedPower; set => SetReceivedPower(value); }
|
||||
private int _receivedPower;
|
||||
public float ReceivedPower => NetworkLoad.ReceivingPower;
|
||||
|
||||
public event EventHandler<ReceivedPowerChangedEventArgs>? OnReceivedPowerChanged;
|
||||
public float LastReceived = float.NaN;
|
||||
|
||||
public PowerState.Load NetworkLoad { get; } = new();
|
||||
|
||||
protected override void AddSelfToNet(IPowerNet powerNet)
|
||||
{
|
||||
@@ -48,44 +41,5 @@ namespace Content.Server.Power.Components
|
||||
{
|
||||
powerNet.RemoveConsumer(this);
|
||||
}
|
||||
|
||||
private void SetDrawRate(int newDrawRate)
|
||||
{
|
||||
var oldDrawRate = DrawRate;
|
||||
_drawRate = newDrawRate; //must be set before updating powernet, as it checks the DrawRate of every consumer
|
||||
Net.UpdateConsumerDraw(this, oldDrawRate, newDrawRate);
|
||||
}
|
||||
|
||||
private void SetReceivedPower(int newReceivedPower)
|
||||
{
|
||||
Debug.Assert(newReceivedPower >= 0 && newReceivedPower <= DrawRate);
|
||||
if(_receivedPower == newReceivedPower) return;
|
||||
_receivedPower = newReceivedPower;
|
||||
OnReceivedPowerChanged?.Invoke(this, new ReceivedPowerChangedEventArgs(_drawRate, _receivedPower));
|
||||
}
|
||||
|
||||
private void SetPriority(Priority newPriority)
|
||||
{
|
||||
Net.UpdateConsumerPriority(this, Priority, newPriority);
|
||||
_priority = newPriority;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Priority
|
||||
{
|
||||
First,
|
||||
Last,
|
||||
}
|
||||
|
||||
public class ReceivedPowerChangedEventArgs : EventArgs
|
||||
{
|
||||
public readonly int DrawRate;
|
||||
public readonly int ReceivedPower;
|
||||
|
||||
public ReceivedPowerChangedEventArgs(int drawRate, int receivedPower)
|
||||
{
|
||||
DrawRate = drawRate;
|
||||
ReceivedPower = receivedPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
119
Content.Server/Power/Components/PowerNetworkBatteryComponent.cs
Normal file
119
Content.Server/Power/Components/PowerNetworkBatteryComponent.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using Content.Server.Power.Pow3r;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Glue component that manages the pow3r network node for batteries that are connected to the power network.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This needs components like <see cref="BatteryChargerComponent"/> to work correctly,
|
||||
/// and battery storage should be handed off to components like <see cref="BatteryComponent"/>.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class PowerNetworkBatteryComponent : Component
|
||||
{
|
||||
public override string Name => "PowerNetworkBattery";
|
||||
|
||||
[DataField("maxChargeRate")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MaxChargeRate
|
||||
{
|
||||
get => NetworkBattery.MaxChargeRate;
|
||||
set => NetworkBattery.MaxChargeRate = value;
|
||||
}
|
||||
|
||||
[DataField("maxSupply")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MaxSupply
|
||||
{
|
||||
get => NetworkBattery.MaxSupply;
|
||||
set => NetworkBattery.MaxSupply = value;
|
||||
}
|
||||
|
||||
[DataField("supplyRampTolerance")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float SupplyRampTolerance
|
||||
{
|
||||
get => NetworkBattery.SupplyRampTolerance;
|
||||
set => NetworkBattery.SupplyRampTolerance = value;
|
||||
}
|
||||
|
||||
[DataField("supplyRampRate")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float SupplyRampRate
|
||||
{
|
||||
get => NetworkBattery.SupplyRampRate;
|
||||
set => NetworkBattery.SupplyRampRate = value;
|
||||
}
|
||||
|
||||
[DataField("supplyRampPosition")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float SupplyRampPosition
|
||||
{
|
||||
get => NetworkBattery.SupplyRampPosition;
|
||||
set => NetworkBattery.SupplyRampPosition = value;
|
||||
}
|
||||
|
||||
[DataField("currentSupply")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float CurrentSupply
|
||||
{
|
||||
get => NetworkBattery.CurrentSupply;
|
||||
set => NetworkBattery.CurrentSupply = value;
|
||||
}
|
||||
|
||||
[DataField("currentReceiving")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float CurrentReceiving
|
||||
{
|
||||
get => NetworkBattery.CurrentReceiving;
|
||||
set => NetworkBattery.CurrentReceiving = value;
|
||||
}
|
||||
|
||||
[DataField("loadingNetworkDemand")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float LoadingNetworkDemand
|
||||
{
|
||||
get => NetworkBattery.LoadingNetworkDemand;
|
||||
set => NetworkBattery.LoadingNetworkDemand = value;
|
||||
}
|
||||
|
||||
[DataField("enabled")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Enabled
|
||||
{
|
||||
get => NetworkBattery.Enabled;
|
||||
set => NetworkBattery.Enabled = value;
|
||||
}
|
||||
|
||||
[DataField("canCharge")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanCharge
|
||||
{
|
||||
get => NetworkBattery.CanCharge;
|
||||
set => NetworkBattery.CanCharge = value;
|
||||
}
|
||||
|
||||
[DataField("canDisharge")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanDischarge
|
||||
{
|
||||
get => NetworkBattery.CanDischarge;
|
||||
set => NetworkBattery.CanDischarge = value;
|
||||
}
|
||||
|
||||
[DataField("efficiency")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Efficiency
|
||||
{
|
||||
get => NetworkBattery.Efficiency;
|
||||
set => NetworkBattery.Efficiency = value;
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public PowerState.Battery NetworkBattery { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.APC;
|
||||
using Content.Server.APC.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Relays <see cref="PowerReceiverComponent"/>s in an area to a <see cref="IApcNet"/> so they can receive power.
|
||||
/// </summary>
|
||||
public interface IPowerProvider
|
||||
{
|
||||
void AddReceiver(PowerReceiverComponent receiver);
|
||||
|
||||
void RemoveReceiver(PowerReceiverComponent receiver);
|
||||
|
||||
void UpdateReceiverLoad(int oldLoad, int newLoad);
|
||||
|
||||
public IEntity? ProviderOwner { get; }
|
||||
|
||||
public bool HasApcPower { get; }
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public class PowerProviderComponent : BaseApcNetComponent, IPowerProvider
|
||||
{
|
||||
public override string Name => "PowerProvider";
|
||||
|
||||
public IEntity ProviderOwner => Owner;
|
||||
|
||||
[ViewVariables]
|
||||
public bool HasApcPower => Net.Powered;
|
||||
|
||||
/// <summary>
|
||||
/// The max distance this can transmit power to <see cref="PowerReceiverComponent"/>s from.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PowerTransferRange { get => _powerTransferRange; set => SetPowerTransferRange(value); }
|
||||
[DataField("powerTransferRange")]
|
||||
private int _powerTransferRange = 3;
|
||||
|
||||
[ViewVariables]
|
||||
public IReadOnlyList<PowerReceiverComponent> LinkedReceivers => _linkedReceivers;
|
||||
private List<PowerReceiverComponent> _linkedReceivers = new();
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="PowerReceiverComponent"/>s should consider connecting to this.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Connectable { get; private set; } = true;
|
||||
|
||||
public static readonly IPowerProvider NullProvider = new NullPowerProvider();
|
||||
|
||||
public void AddReceiver(PowerReceiverComponent receiver)
|
||||
{
|
||||
var oldLoad = GetTotalLoad();
|
||||
_linkedReceivers.Add(receiver);
|
||||
var newLoad = oldLoad + receiver.Load;
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
public void RemoveReceiver(PowerReceiverComponent receiver)
|
||||
{
|
||||
var oldLoad = GetTotalLoad();
|
||||
_linkedReceivers.Remove(receiver);
|
||||
var newLoad = oldLoad - receiver.Load;
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
public void UpdateReceiverLoad(int oldLoad, int newLoad)
|
||||
{
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
foreach (var receiver in FindAvailableReceivers())
|
||||
{
|
||||
receiver.Provider = this;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
Connectable = false;
|
||||
var receivers = _linkedReceivers.ToArray();
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.ClearProvider();
|
||||
}
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.TryFindAndSetProvider();
|
||||
}
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
private List<PowerReceiverComponent> FindAvailableReceivers()
|
||||
{
|
||||
var nearbyEntities = IoCManager.Resolve<IEntityLookup>()
|
||||
.GetEntitiesInRange(Owner, PowerTransferRange);
|
||||
|
||||
var receivers = new List<PowerReceiverComponent>();
|
||||
|
||||
foreach (var entity in nearbyEntities)
|
||||
{
|
||||
if (entity.TryGetComponent<PowerReceiverComponent>(out var receiver) &&
|
||||
receiver.Connectable &&
|
||||
receiver.NeedsProvider &&
|
||||
receiver.Owner.Transform.Coordinates.TryDistance(Owner.EntityManager, Owner.Transform.Coordinates, out var distance) &&
|
||||
distance < Math.Min(PowerTransferRange, receiver.PowerReceptionRange))
|
||||
{
|
||||
receivers.Add(receiver);
|
||||
}
|
||||
}
|
||||
return receivers;
|
||||
}
|
||||
|
||||
protected override void AddSelfToNet(IApcNet apcNet)
|
||||
{
|
||||
apcNet.AddPowerProvider(this);
|
||||
}
|
||||
|
||||
protected override void RemoveSelfFromNet(IApcNet apcNet)
|
||||
{
|
||||
apcNet.RemovePowerProvider(this);
|
||||
}
|
||||
|
||||
private void SetPowerTransferRange(int newPowerTransferRange)
|
||||
{
|
||||
var receivers = _linkedReceivers.ToArray();
|
||||
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.ClearProvider();
|
||||
}
|
||||
_powerTransferRange = newPowerTransferRange;
|
||||
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.TryFindAndSetProvider();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetTotalLoad()
|
||||
{
|
||||
var load = 0;
|
||||
foreach (var receiver in _linkedReceivers)
|
||||
{
|
||||
load += receiver.Load;
|
||||
}
|
||||
return load;
|
||||
}
|
||||
|
||||
private class NullPowerProvider : IPowerProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// It is important that this returns false, so <see cref="PowerReceiverComponent"/>s with a <see cref="NullPowerProvider"/> have no power.
|
||||
/// </summary>
|
||||
public bool HasApcPower => false;
|
||||
|
||||
public void AddReceiver(PowerReceiverComponent receiver) { }
|
||||
public void RemoveReceiver(PowerReceiverComponent receiver) { }
|
||||
public void UpdateReceiverLoad(int oldLoad, int newLoad) { }
|
||||
public IEntity? ProviderOwner => default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Content.Server.Power.Pow3r;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -12,9 +13,45 @@ namespace Content.Server.Power.Components
|
||||
public override string Name => "PowerSupplier";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int SupplyRate { get => _supplyRate; set => SetSupplyRate(value); }
|
||||
[DataField("supplyRate")]
|
||||
private int _supplyRate;
|
||||
public float MaxSupply { get => NetworkSupply.MaxSupply; set => NetworkSupply.MaxSupply = value; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("supplyRampTolerance")]
|
||||
public float SupplyRampTolerance
|
||||
{
|
||||
get => NetworkSupply.SupplyRampTolerance;
|
||||
set => NetworkSupply.SupplyRampTolerance = value;
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("supplyRampRate")]
|
||||
public float SupplyRampRate
|
||||
{
|
||||
get => NetworkSupply.SupplyRampRate;
|
||||
set => NetworkSupply.SupplyRampRate = value;
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("supplyRampPosition")]
|
||||
public float SupplyRampPosition
|
||||
{
|
||||
get => NetworkSupply.SupplyRampPosition;
|
||||
set => NetworkSupply.SupplyRampPosition = value;
|
||||
}
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("enabled")]
|
||||
public bool Enabled
|
||||
{
|
||||
get => NetworkSupply.Enabled;
|
||||
set => NetworkSupply.Enabled = value;
|
||||
}
|
||||
|
||||
[ViewVariables] public float CurrentSupply => NetworkSupply.CurrentSupply;
|
||||
|
||||
[ViewVariables]
|
||||
public PowerState.Supply NetworkSupply { get; } = new();
|
||||
|
||||
protected override void AddSelfToNet(IPowerNet powerNet)
|
||||
{
|
||||
@@ -25,11 +62,5 @@ namespace Content.Server.Power.Components
|
||||
{
|
||||
powerNet.RemoveSupplier(this);
|
||||
}
|
||||
|
||||
private void SetSupplyRate(int newSupplyRate)
|
||||
{
|
||||
Net.UpdateSupplierSupply(this, SupplyRate, newSupplyRate);
|
||||
_supplyRate = newSupplyRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#nullable enable
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Battery.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.Battery
|
||||
namespace Content.Server.Power
|
||||
{
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public class DrainAllBatteriesCommand : IConsoleCommand
|
||||
@@ -23,8 +23,8 @@ namespace Content.Server.Battery
|
||||
return;
|
||||
}
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
foreach (var batteryComp in entityManager.ComponentManager.EntityQuery<BatteryComponent>())
|
||||
var comp = IoCManager.Resolve<IComponentManager>();
|
||||
foreach (var batteryComp in comp.EntityQuery<BatteryComponent>())
|
||||
{
|
||||
batteryComp.CurrentCharge = 0;
|
||||
}
|
||||
42
Content.Server/Power/EntitySystems/BatterySystem.cs
Normal file
42
Content.Server/Power/EntitySystems/BatterySystem.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
#nullable enable
|
||||
using Content.Server.Power.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Power.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class BatterySystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BatteryComponent, NetworkBatteryPreSync>(PreSync);
|
||||
SubscribeLocalEvent<BatteryComponent, NetworkBatteryPostSync>(PostSync);
|
||||
}
|
||||
|
||||
private void PreSync(EntityUid uid, BatteryComponent component, NetworkBatteryPreSync args)
|
||||
{
|
||||
var networkBattery = ComponentManager.GetComponent<PowerNetworkBatteryComponent>(uid);
|
||||
|
||||
networkBattery.NetworkBattery.Capacity = component.MaxCharge;
|
||||
networkBattery.NetworkBattery.CurrentStorage = component.CurrentCharge;
|
||||
}
|
||||
|
||||
private void PostSync(EntityUid uid, BatteryComponent component, NetworkBatteryPostSync args)
|
||||
{
|
||||
var networkBattery = ComponentManager.GetComponent<PowerNetworkBatteryComponent>(uid);
|
||||
|
||||
component.CurrentCharge = networkBattery.NetworkBattery.CurrentStorage;
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var comp in ComponentManager.EntityQuery<BatteryComponent>())
|
||||
{
|
||||
comp.OnUpdate(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Content.Server/Power/EntitySystems/CableVisSystem.cs
Normal file
85
Content.Server/Power/EntitySystems/CableVisSystem.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.Nodes;
|
||||
using Content.Shared.Wires;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Power.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class CableVisSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private readonly HashSet<EntityUid> _toUpdate = new();
|
||||
|
||||
public void QueueUpdate(EntityUid uid)
|
||||
{
|
||||
_toUpdate.Add(uid);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesAfter.Add(typeof(NodeGroupSystem));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var uid in _toUpdate)
|
||||
{
|
||||
if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|
||||
|| !ComponentManager.TryGetComponent(uid, out CableVisComponent? cableVis)
|
||||
|| !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cableVis.Node == null)
|
||||
continue;
|
||||
|
||||
var mask = WireVisDirFlags.None;
|
||||
|
||||
var transform = ComponentManager.GetComponent<ITransformComponent>(uid);
|
||||
var grid = _mapManager.GetGrid(transform.GridID);
|
||||
var tile = grid.TileIndicesFor(transform.Coordinates);
|
||||
var node = nodeContainer.GetNode<CableNode>(cableVis.Node);
|
||||
|
||||
foreach (var reachable in node.ReachableNodes)
|
||||
{
|
||||
if (reachable is not CableNode)
|
||||
continue;
|
||||
|
||||
var otherTransform = reachable.Owner.Transform;
|
||||
if (otherTransform.GridID != grid.Index)
|
||||
continue;
|
||||
|
||||
var otherTile = grid.TileIndicesFor(otherTransform.Coordinates);
|
||||
var diff = otherTile - tile;
|
||||
|
||||
mask |= diff switch
|
||||
{
|
||||
(0, 1) => WireVisDirFlags.North,
|
||||
(0, -1) => WireVisDirFlags.South,
|
||||
(1, 0) => WireVisDirFlags.East,
|
||||
(-1, 0) => WireVisDirFlags.West,
|
||||
_ => WireVisDirFlags.None
|
||||
};
|
||||
}
|
||||
|
||||
appearance.SetData(WireVisVisuals.ConnectedMask, mask);
|
||||
}
|
||||
|
||||
_toUpdate.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
#nullable enable
|
||||
using Content.Server.APC.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.APC
|
||||
namespace Content.Server.Power.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class PowerApcSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesAfter.Add(typeof(PowerNetSystem));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var apc in ComponentManager.EntityQuery<ApcComponent>(false))
|
||||
foreach (var apc in ComponentManager.EntityQuery<ApcComponent>())
|
||||
{
|
||||
apc.Update();
|
||||
}
|
||||
@@ -1,20 +1,351 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.NodeGroups;
|
||||
using Content.Server.Power.Pow3r;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.Power.EntitySystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages power networks, power state, and all power components.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class PowerNetSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPowerNetManager _powerNetManager = default!;
|
||||
private readonly PowerState _powerState = new();
|
||||
private readonly HashSet<PowerNet> _powerNetReconnectQueue = new();
|
||||
private readonly HashSet<ApcNet> _apcNetReconnectQueue = new();
|
||||
|
||||
private int _nextId = 1;
|
||||
private readonly BatteryRampPegSolver _solver = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesAfter.Add(typeof(NodeGroupSystem));
|
||||
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, ComponentInit>(ApcPowerReceiverInit);
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, ComponentShutdown>(ApcPowerReceiverShutdown);
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, EntityPausedEvent>(ApcPowerReceiverPaused);
|
||||
SubscribeLocalEvent<PowerNetworkBatteryComponent, ComponentInit>(BatteryInit);
|
||||
SubscribeLocalEvent<PowerNetworkBatteryComponent, ComponentShutdown>(BatteryShutdown);
|
||||
SubscribeLocalEvent<PowerNetworkBatteryComponent, EntityPausedEvent>(BatteryPaused);
|
||||
SubscribeLocalEvent<PowerConsumerComponent, ComponentInit>(PowerConsumerInit);
|
||||
SubscribeLocalEvent<PowerConsumerComponent, ComponentShutdown>(PowerConsumerShutdown);
|
||||
SubscribeLocalEvent<PowerConsumerComponent, EntityPausedEvent>(PowerConsumerPaused);
|
||||
SubscribeLocalEvent<PowerSupplierComponent, ComponentInit>(PowerSupplierInit);
|
||||
SubscribeLocalEvent<PowerSupplierComponent, ComponentShutdown>(PowerSupplierShutdown);
|
||||
SubscribeLocalEvent<PowerSupplierComponent, EntityPausedEvent>(PowerSupplierPaused);
|
||||
}
|
||||
|
||||
private void ApcPowerReceiverInit(EntityUid uid, ApcPowerReceiverComponent component, ComponentInit args)
|
||||
{
|
||||
AllocLoad(component.NetworkLoad);
|
||||
}
|
||||
|
||||
private void ApcPowerReceiverShutdown(EntityUid uid, ApcPowerReceiverComponent component,
|
||||
ComponentShutdown args)
|
||||
{
|
||||
_powerState.Loads.Remove(component.NetworkLoad.Id);
|
||||
}
|
||||
|
||||
private static void ApcPowerReceiverPaused(
|
||||
EntityUid uid,
|
||||
ApcPowerReceiverComponent component,
|
||||
EntityPausedEvent args)
|
||||
{
|
||||
component.NetworkLoad.Paused = args.Paused;
|
||||
}
|
||||
|
||||
private void BatteryInit(EntityUid uid, PowerNetworkBatteryComponent component, ComponentInit args)
|
||||
{
|
||||
AllocBattery(component.NetworkBattery);
|
||||
}
|
||||
|
||||
private void BatteryShutdown(EntityUid uid, PowerNetworkBatteryComponent component, ComponentShutdown args)
|
||||
{
|
||||
_powerState.Batteries.Remove(component.NetworkBattery.Id);
|
||||
}
|
||||
|
||||
private static void BatteryPaused(EntityUid uid, PowerNetworkBatteryComponent component, EntityPausedEvent args)
|
||||
{
|
||||
component.NetworkBattery.Paused = args.Paused;
|
||||
}
|
||||
|
||||
private void PowerConsumerInit(EntityUid uid, PowerConsumerComponent component, ComponentInit args)
|
||||
{
|
||||
AllocLoad(component.NetworkLoad);
|
||||
}
|
||||
|
||||
private void PowerConsumerShutdown(EntityUid uid, PowerConsumerComponent component, ComponentShutdown args)
|
||||
{
|
||||
_powerState.Loads.Remove(component.NetworkLoad.Id);
|
||||
}
|
||||
|
||||
private static void PowerConsumerPaused(EntityUid uid, PowerConsumerComponent component, EntityPausedEvent args)
|
||||
{
|
||||
component.NetworkLoad.Paused = args.Paused;
|
||||
}
|
||||
|
||||
private void PowerSupplierInit(EntityUid uid, PowerSupplierComponent component, ComponentInit args)
|
||||
{
|
||||
AllocSupply(component.NetworkSupply);
|
||||
}
|
||||
|
||||
private void PowerSupplierShutdown(EntityUid uid, PowerSupplierComponent component, ComponentShutdown args)
|
||||
{
|
||||
_powerState.Supplies.Remove(component.NetworkSupply.Id);
|
||||
}
|
||||
|
||||
private static void PowerSupplierPaused(EntityUid uid, PowerSupplierComponent component, EntityPausedEvent args)
|
||||
{
|
||||
component.NetworkSupply.Paused = args.Paused;
|
||||
}
|
||||
|
||||
public void InitPowerNet(PowerNet powerNet)
|
||||
{
|
||||
AllocNetwork(powerNet.NetworkNode);
|
||||
}
|
||||
|
||||
public void DestroyPowerNet(PowerNet powerNet)
|
||||
{
|
||||
_powerState.Networks.Remove(powerNet.NetworkNode.Id);
|
||||
}
|
||||
|
||||
public void QueueReconnectPowerNet(PowerNet powerNet)
|
||||
{
|
||||
_powerNetReconnectQueue.Add(powerNet);
|
||||
}
|
||||
|
||||
public void InitApcNet(ApcNet apcNet)
|
||||
{
|
||||
AllocNetwork(apcNet.NetworkNode);
|
||||
}
|
||||
|
||||
public void DestroyApcNet(ApcNet apcNet)
|
||||
{
|
||||
_powerState.Networks.Remove(apcNet.NetworkNode.Id);
|
||||
}
|
||||
|
||||
public void QueueReconnectApcNet(ApcNet apcNet)
|
||||
{
|
||||
_apcNetReconnectQueue.Add(apcNet);
|
||||
}
|
||||
|
||||
public PowerStatistics GetStatistics()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
CountBatteries = _powerState.Batteries.Count,
|
||||
CountLoads = _powerState.Loads.Count,
|
||||
CountNetworks = _powerState.Networks.Count,
|
||||
CountSupplies = _powerState.Supplies.Count
|
||||
};
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
_powerNetManager.Update(frameTime);
|
||||
|
||||
// Reconnect networks.
|
||||
{
|
||||
foreach (var apcNet in _apcNetReconnectQueue)
|
||||
{
|
||||
if (apcNet.Removed)
|
||||
continue;
|
||||
|
||||
DoReconnectApcNet(apcNet);
|
||||
}
|
||||
|
||||
_apcNetReconnectQueue.Clear();
|
||||
|
||||
foreach (var powerNet in _powerNetReconnectQueue)
|
||||
{
|
||||
if (powerNet.Removed)
|
||||
continue;
|
||||
|
||||
DoReconnectPowerNet(powerNet);
|
||||
}
|
||||
|
||||
_powerNetReconnectQueue.Clear();
|
||||
}
|
||||
|
||||
// Synchronize batteries
|
||||
foreach (var battery in ComponentManager.EntityQuery<PowerNetworkBatteryComponent>())
|
||||
{
|
||||
RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPreSync());
|
||||
}
|
||||
|
||||
// Run power solver.
|
||||
_solver.Tick(frameTime, _powerState);
|
||||
|
||||
// Synchronize batteries, the other way around.
|
||||
foreach (var battery in ComponentManager.EntityQuery<PowerNetworkBatteryComponent>())
|
||||
{
|
||||
RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPostSync());
|
||||
}
|
||||
|
||||
// Send events where necessary.
|
||||
{
|
||||
foreach (var apcReceiver in ComponentManager.EntityQuery<ApcPowerReceiverComponent>())
|
||||
{
|
||||
var recv = apcReceiver.NetworkLoad.ReceivingPower;
|
||||
ref var last = ref apcReceiver.LastPowerReceived;
|
||||
|
||||
if (!MathHelper.CloseTo(recv, last))
|
||||
{
|
||||
last = recv;
|
||||
apcReceiver.ApcPowerChanged();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var consumer in ComponentManager.EntityQuery<PowerConsumerComponent>())
|
||||
{
|
||||
var newRecv = consumer.NetworkLoad.ReceivingPower;
|
||||
ref var lastRecv = ref consumer.LastReceived;
|
||||
if (!MathHelper.CloseTo(lastRecv, newRecv))
|
||||
{
|
||||
lastRecv = newRecv;
|
||||
var msg = new PowerConsumerReceivedChanged(newRecv, consumer.DrawRate);
|
||||
RaiseLocalEvent(consumer.Owner.Uid, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AllocLoad(PowerState.Load load)
|
||||
{
|
||||
load.Id = AllocId();
|
||||
_powerState.Loads.Add(load.Id, load);
|
||||
}
|
||||
|
||||
private void AllocSupply(PowerState.Supply supply)
|
||||
{
|
||||
supply.Id = AllocId();
|
||||
_powerState.Supplies.Add(supply.Id, supply);
|
||||
}
|
||||
|
||||
private void AllocBattery(PowerState.Battery battery)
|
||||
{
|
||||
battery.Id = AllocId();
|
||||
_powerState.Batteries.Add(battery.Id, battery);
|
||||
}
|
||||
|
||||
private void AllocNetwork(PowerState.Network network)
|
||||
{
|
||||
network.Id = AllocId();
|
||||
_powerState.Networks.Add(network.Id, network);
|
||||
}
|
||||
|
||||
private static void DoReconnectApcNet(ApcNet net)
|
||||
{
|
||||
var netNode = net.NetworkNode;
|
||||
|
||||
netNode.Loads.Clear();
|
||||
netNode.BatteriesDischarging.Clear();
|
||||
netNode.BatteriesCharging.Clear();
|
||||
netNode.Supplies.Clear();
|
||||
|
||||
foreach (var provider in net.Providers)
|
||||
{
|
||||
foreach (var receiver in provider.LinkedReceivers)
|
||||
{
|
||||
netNode.Loads.Add(receiver.NetworkLoad.Id);
|
||||
receiver.NetworkLoad.LinkedNetwork = netNode.Id;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var apc in net.Apcs)
|
||||
{
|
||||
var netBattery = apc.Owner.GetComponent<PowerNetworkBatteryComponent>();
|
||||
netNode.BatteriesDischarging.Add(netBattery.NetworkBattery.Id);
|
||||
netBattery.NetworkBattery.LinkedNetworkDischarging = netNode.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoReconnectPowerNet(PowerNet net)
|
||||
{
|
||||
var netNode = net.NetworkNode;
|
||||
|
||||
netNode.Loads.Clear();
|
||||
netNode.Supplies.Clear();
|
||||
netNode.BatteriesCharging.Clear();
|
||||
netNode.BatteriesDischarging.Clear();
|
||||
|
||||
foreach (var consumer in net.Consumers)
|
||||
{
|
||||
netNode.Loads.Add(consumer.NetworkLoad.Id);
|
||||
consumer.NetworkLoad.LinkedNetwork = netNode.Id;
|
||||
}
|
||||
|
||||
foreach (var supplier in net.Suppliers)
|
||||
{
|
||||
netNode.Supplies.Add(supplier.NetworkSupply.Id);
|
||||
supplier.NetworkSupply.LinkedNetwork = netNode.Id;
|
||||
}
|
||||
|
||||
foreach (var charger in net.Chargers)
|
||||
{
|
||||
var battery = charger.Owner.GetComponent<PowerNetworkBatteryComponent>();
|
||||
netNode.BatteriesCharging.Add(battery.NetworkBattery.Id);
|
||||
battery.NetworkBattery.LinkedNetworkCharging = netNode.Id;
|
||||
}
|
||||
|
||||
foreach (var discharger in net.Dischargers)
|
||||
{
|
||||
var battery = discharger.Owner.GetComponent<PowerNetworkBatteryComponent>();
|
||||
netNode.BatteriesDischarging.Add(battery.NetworkBattery.Id);
|
||||
battery.NetworkBattery.LinkedNetworkDischarging = netNode.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private PowerState.NodeId AllocId()
|
||||
{
|
||||
return new(_nextId++);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised before power network simulation happens, to synchronize battery state from
|
||||
/// components like <see cref="BatteryComponent"/> into <see cref="PowerNetworkBatteryComponent"/>.
|
||||
/// </summary>
|
||||
public sealed class NetworkBatteryPreSync : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised after power network simulation happens, to synchronize battery charge changes from
|
||||
/// <see cref="PowerNetworkBatteryComponent"/> to components like <see cref="BatteryComponent"/>.
|
||||
/// </summary>
|
||||
public sealed class NetworkBatteryPostSync : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the amount of receiving power on a <see cref="PowerConsumerComponent"/> changes.
|
||||
/// </summary>
|
||||
public sealed class PowerConsumerReceivedChanged : EntityEventArgs
|
||||
{
|
||||
public float ReceivedPower { get; }
|
||||
public float DrawRate { get; }
|
||||
|
||||
public PowerConsumerReceivedChanged(float receivedPower, float drawRate)
|
||||
{
|
||||
ReceivedPower = receivedPower;
|
||||
DrawRate = drawRate;
|
||||
}
|
||||
}
|
||||
|
||||
public struct PowerStatistics
|
||||
{
|
||||
public int CountNetworks;
|
||||
public int CountLoads;
|
||||
public int CountSupplies;
|
||||
public int CountBatteries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace Content.Server.Power.EntitySystems
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PowerReceiverComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
|
||||
SubscribeLocalEvent<ApcPowerReceiverComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
|
||||
}
|
||||
|
||||
private static void BodyTypeChanged(
|
||||
EntityUid uid,
|
||||
PowerReceiverComponent component,
|
||||
ApcPowerReceiverComponent component,
|
||||
PhysicsBodyTypeChangedEvent args)
|
||||
{
|
||||
component.AnchorUpdate();
|
||||
|
||||
112
Content.Server/Power/NodeGroups/ApcNet.cs
Normal file
112
Content.Server/Power/NodeGroups/ApcNet.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Power.Pow3r;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Power.NodeGroups
|
||||
{
|
||||
public interface IApcNet
|
||||
{
|
||||
void AddApc(ApcComponent apc);
|
||||
|
||||
void RemoveApc(ApcComponent apc);
|
||||
|
||||
void AddPowerProvider(ApcPowerProviderComponent provider);
|
||||
|
||||
void RemovePowerProvider(ApcPowerProviderComponent provider);
|
||||
|
||||
void QueueNetworkReconnect();
|
||||
|
||||
PowerState.Network NetworkNode { get; }
|
||||
|
||||
GridId? GridId { get; }
|
||||
}
|
||||
|
||||
[NodeGroup(NodeGroupID.Apc)]
|
||||
[UsedImplicitly]
|
||||
public class ApcNet : BaseNetConnectorNodeGroup<BaseApcNetComponent, IApcNet>, IApcNet
|
||||
{
|
||||
private readonly PowerNetSystem _powerNetSystem = EntitySystem.Get<PowerNetSystem>();
|
||||
|
||||
[ViewVariables] public readonly List<ApcComponent> Apcs = new();
|
||||
|
||||
[ViewVariables] public readonly List<ApcPowerProviderComponent> Providers = new();
|
||||
|
||||
//Debug property
|
||||
[ViewVariables] private int TotalReceivers => Providers.Sum(provider => provider.LinkedReceivers.Count);
|
||||
|
||||
[ViewVariables]
|
||||
private IEnumerable<ApcPowerReceiverComponent> AllReceivers =>
|
||||
Providers.SelectMany(provider => provider.LinkedReceivers);
|
||||
|
||||
GridId? IApcNet.GridId => GridId;
|
||||
|
||||
[ViewVariables]
|
||||
public PowerState.Network NetworkNode { get; } = new();
|
||||
|
||||
public override void Initialize(Node sourceNode)
|
||||
{
|
||||
base.Initialize(sourceNode);
|
||||
|
||||
_powerNetSystem.InitApcNet(this);
|
||||
}
|
||||
|
||||
public override void AfterRemake(IEnumerable<IGrouping<INodeGroup?, Node>> newGroups)
|
||||
{
|
||||
base.AfterRemake(newGroups);
|
||||
|
||||
_powerNetSystem.DestroyApcNet(this);
|
||||
}
|
||||
|
||||
public void AddApc(ApcComponent apc)
|
||||
{
|
||||
if (apc.Owner.TryGetComponent(out PowerNetworkBatteryComponent? netBattery))
|
||||
netBattery.NetworkBattery.LinkedNetworkDischarging = default;
|
||||
|
||||
_powerNetSystem.QueueReconnectApcNet(this);
|
||||
Apcs.Add(apc);
|
||||
}
|
||||
|
||||
public void RemoveApc(ApcComponent apc)
|
||||
{
|
||||
if (apc.Owner.TryGetComponent(out PowerNetworkBatteryComponent? netBattery))
|
||||
netBattery.NetworkBattery.LinkedNetworkDischarging = default;
|
||||
|
||||
_powerNetSystem.QueueReconnectApcNet(this);
|
||||
Apcs.Remove(apc);
|
||||
}
|
||||
|
||||
public void AddPowerProvider(ApcPowerProviderComponent provider)
|
||||
{
|
||||
Providers.Add(provider);
|
||||
|
||||
_powerNetSystem.QueueReconnectApcNet(this);
|
||||
}
|
||||
|
||||
public void RemovePowerProvider(ApcPowerProviderComponent provider)
|
||||
{
|
||||
Providers.Remove(provider);
|
||||
|
||||
_powerNetSystem.QueueReconnectApcNet(this);
|
||||
}
|
||||
|
||||
public void QueueNetworkReconnect()
|
||||
{
|
||||
_powerNetSystem.QueueReconnectApcNet(this);
|
||||
}
|
||||
|
||||
protected override void SetNetConnectorNet(BaseApcNetComponent netConnectorComponent)
|
||||
{
|
||||
netConnectorComponent.Net = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Content.Server/Power/NodeGroups/BaseNetConnectorNodeGroup.cs
Normal file
34
Content.Server/Power/NodeGroups/BaseNetConnectorNodeGroup.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.Power.Components;
|
||||
|
||||
namespace Content.Server.Power.NodeGroups
|
||||
{
|
||||
public abstract class BaseNetConnectorNodeGroup<TNetConnector, TNetType> : BaseNodeGroup
|
||||
where TNetConnector : BaseNetConnectorComponent<TNetType>
|
||||
{
|
||||
public override void LoadNodes(List<Node> groupNodes)
|
||||
{
|
||||
base.LoadNodes(groupNodes);
|
||||
|
||||
foreach (var node in groupNodes)
|
||||
{
|
||||
var newNetConnectorComponents = node.Owner
|
||||
.GetAllComponents<TNetConnector>()
|
||||
.Where(powerComp => (powerComp.NodeId == null || powerComp.NodeId == node.Name) &&
|
||||
(NodeGroupID) powerComp.Voltage == node.NodeGroupID)
|
||||
.ToList();
|
||||
|
||||
foreach (var netConnector in newNetConnectorComponents)
|
||||
{
|
||||
SetNetConnectorNet(netConnector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void SetNetConnectorNet(TNetConnector netConnectorComponent);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user