2019-11-13 17:37:46 -05:00
|
|
|
|
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
|
|
|
|
|
// ReSharper disable once RedundantUsingDirective
|
|
|
|
|
|
using Robust.Shared.Utility;
|
|
|
|
|
|
using System.Collections.Generic;
|
2019-07-31 15:02:36 +02:00
|
|
|
|
using System.Linq;
|
2019-04-15 21:11:38 -06:00
|
|
|
|
using Robust.Server.Interfaces.GameObjects;
|
2019-07-31 15:02:36 +02:00
|
|
|
|
using Robust.Shared.GameObjects;
|
2019-04-15 21:11:38 -06:00
|
|
|
|
using Robust.Shared.Interfaces.GameObjects.Components;
|
|
|
|
|
|
using Robust.Shared.IoC;
|
|
|
|
|
|
using Robust.Shared.Log;
|
|
|
|
|
|
using Robust.Shared.Serialization;
|
|
|
|
|
|
using Robust.Shared.ViewVariables;
|
2020-02-07 08:55:27 -08:00
|
|
|
|
using Robust.Shared.Map;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
|
|
|
|
|
namespace Content.Server.GameObjects.Components.Power
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Component that wirelessly connects and powers devices, connects to powernet via node and can be combined with internal storage component
|
|
|
|
|
|
/// </summary>
|
2019-07-31 15:02:36 +02:00
|
|
|
|
[RegisterComponent]
|
|
|
|
|
|
[ComponentReference(typeof(PowerDeviceComponent))]
|
2018-02-03 22:35:42 -06:00
|
|
|
|
public class PowerProviderComponent : PowerDeviceComponent
|
|
|
|
|
|
{
|
|
|
|
|
|
public override string Name => "PowerProvider";
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2020-02-06 08:50:52 -05:00
|
|
|
|
protected override DrawTypes DefaultDrawType => DrawTypes.Node;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
2019-09-19 13:46:01 +02:00
|
|
|
|
protected override bool SaveLoad => false;
|
|
|
|
|
|
|
2018-02-03 22:35:42 -06:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Variable that determines the range that the power provider will try to supply power to
|
|
|
|
|
|
/// </summary>
|
2018-09-09 15:34:43 +02:00
|
|
|
|
[ViewVariables]
|
2018-07-26 23:38:16 +02:00
|
|
|
|
public int PowerRange
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _range;
|
|
|
|
|
|
private set => _range = value;
|
|
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-07-26 23:38:16 +02:00
|
|
|
|
private int _range = 0;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List storing all the power devices that we are currently providing power to
|
|
|
|
|
|
/// </summary>
|
2018-08-31 08:52:48 +02:00
|
|
|
|
public SortedSet<PowerDeviceComponent> DeviceLoadList =
|
|
|
|
|
|
new SortedSet<PowerDeviceComponent>(new Powernet.DevicePriorityCompare());
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
2018-05-27 21:45:31 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// List of devices in range that we "advertised" to.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public HashSet<PowerDeviceComponent> AdvertisedDevices = new HashSet<PowerDeviceComponent>();
|
|
|
|
|
|
|
2018-02-03 22:35:42 -06:00
|
|
|
|
public List<PowerDeviceComponent> DepoweredDevices = new List<PowerDeviceComponent>();
|
|
|
|
|
|
|
|
|
|
|
|
public override Powernet.Priority Priority { get; protected set; } = Powernet.Priority.Provider;
|
|
|
|
|
|
|
2018-08-31 08:52:48 +02:00
|
|
|
|
private bool _mainBreaker = true;
|
|
|
|
|
|
|
2018-09-09 15:34:43 +02:00
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
2018-08-31 08:52:48 +02:00
|
|
|
|
public bool MainBreaker
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _mainBreaker;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_mainBreaker == value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_mainBreaker = value;
|
|
|
|
|
|
if (!value)
|
|
|
|
|
|
{
|
|
|
|
|
|
DepowerAllDevices();
|
|
|
|
|
|
Load = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Load = TheoreticalLoad;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private float _theoreticalLoad = 0f;
|
|
|
|
|
|
|
2018-09-09 15:34:43 +02:00
|
|
|
|
[ViewVariables]
|
2018-08-31 08:52:48 +02:00
|
|
|
|
public float TheoreticalLoad
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _theoreticalLoad;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_theoreticalLoad = value;
|
|
|
|
|
|
if (MainBreaker)
|
|
|
|
|
|
{
|
|
|
|
|
|
Load = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 21:45:31 +02:00
|
|
|
|
public PowerProviderComponent()
|
2018-05-27 16:44:50 +02:00
|
|
|
|
{
|
2018-05-27 21:45:31 +02:00
|
|
|
|
Load = 0;
|
|
|
|
|
|
}
|
2018-05-27 16:44:50 +02:00
|
|
|
|
|
2019-09-18 11:29:12 -07:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
protected override void Shutdown()
|
2018-05-27 21:45:31 +02:00
|
|
|
|
{
|
|
|
|
|
|
base.Shutdown();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var device in AdvertisedDevices.ToList())
|
2018-05-27 16:44:50 +02:00
|
|
|
|
{
|
|
|
|
|
|
device.RemoveProvider(this);
|
|
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-05-27 21:45:31 +02:00
|
|
|
|
AdvertisedDevices.Clear();
|
2018-05-27 16:44:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-26 23:38:16 +02:00
|
|
|
|
public override void ExposeData(ObjectSerializer serializer)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-07-26 23:38:16 +02:00
|
|
|
|
base.ExposeData(serializer);
|
|
|
|
|
|
|
|
|
|
|
|
serializer.DataField(ref _range, "range", 0);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 16:44:50 +02:00
|
|
|
|
internal override void ProcessInternalPower(float frametime)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
// Right now let's just assume that APCs don't have a power demand themselves and as such they're always marked as powered.
|
|
|
|
|
|
InternalPowered = true;
|
|
|
|
|
|
if (!Owner.TryGetComponent<PowerStorageComponent>(out var storage))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-31 08:52:48 +02:00
|
|
|
|
if (!MainBreaker)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 16:44:50 +02:00
|
|
|
|
if (ExternalPowered)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
|
|
|
|
|
PowerAllDevices();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-31 08:52:48 +02:00
|
|
|
|
if (storage.CanDeductCharge(TheoreticalLoad * frametime))
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
PowerAllDevices();
|
2018-08-31 08:52:48 +02:00
|
|
|
|
storage.DeductCharge(TheoreticalLoad * frametime);
|
2018-05-27 16:44:50 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 19:33:27 +02:00
|
|
|
|
var remainingEnergy = storage.AvailableCharge(frametime);
|
|
|
|
|
|
var usedEnergy = 0f;
|
2018-05-27 16:44:50 +02:00
|
|
|
|
foreach (var device in DeviceLoadList)
|
|
|
|
|
|
{
|
2018-05-27 19:33:27 +02:00
|
|
|
|
var deviceLoad = device.Load * frametime;
|
|
|
|
|
|
if (deviceLoad > remainingEnergy)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
device.ExternalPowered = false;
|
|
|
|
|
|
DepoweredDevices.Add(device);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
2018-05-27 16:44:50 +02:00
|
|
|
|
else
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
if (!device.ExternalPowered)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
DepoweredDevices.Remove(device);
|
2018-05-27 19:33:27 +02:00
|
|
|
|
device.ExternalPowered = true;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-05-27 19:33:27 +02:00
|
|
|
|
usedEnergy += deviceLoad;
|
|
|
|
|
|
remainingEnergy -= deviceLoad;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 19:33:27 +02:00
|
|
|
|
storage.DeductCharge(usedEnergy);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-02-03 22:35:42 -06:00
|
|
|
|
private void PowerAllDevices()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var device in DepoweredDevices)
|
|
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
device.ExternalPowered = true;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-02-03 22:35:42 -06:00
|
|
|
|
DepoweredDevices.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DepowerAllDevices()
|
|
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
foreach (var device in DeviceLoadList)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
device.ExternalPowered = false;
|
2018-08-31 08:52:48 +02:00
|
|
|
|
DepoweredDevices.Add(device);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-27 16:44:50 +02:00
|
|
|
|
protected override void PowernetConnect(object sender, PowernetEventArgs eventarg)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
base.PowernetConnect(sender, eventarg);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
|
|
|
|
|
//Find devices within range to take under our control
|
2020-02-06 08:50:52 -05:00
|
|
|
|
var entMgr = IoCManager.Resolve<IServerEntityManager>();
|
2018-08-02 08:29:55 +02:00
|
|
|
|
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
2020-02-06 08:50:52 -05:00
|
|
|
|
var entities = entMgr.GetEntitiesInRange(Owner, PowerRange)
|
2018-08-31 08:52:48 +02:00
|
|
|
|
.Where(x => x.HasComponent<PowerDeviceComponent>());
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var entity in entities)
|
|
|
|
|
|
{
|
|
|
|
|
|
var device = entity.GetComponent<PowerDeviceComponent>();
|
2018-04-19 20:23:49 +02:00
|
|
|
|
|
2018-02-03 22:35:42 -06:00
|
|
|
|
//Make sure the device can accept power providers to give it power
|
2018-05-27 16:44:50 +02:00
|
|
|
|
if (device.DrawType == DrawTypes.Provider || device.DrawType == DrawTypes.Both)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 21:45:31 +02:00
|
|
|
|
if (!AdvertisedDevices.Contains(device))
|
|
|
|
|
|
{
|
|
|
|
|
|
device.AddProvider(this);
|
|
|
|
|
|
AdvertisedDevices.Add(device);
|
|
|
|
|
|
}
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-05-27 16:44:50 +02:00
|
|
|
|
protected override void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
base.PowernetDisconnect(sender, eventarg);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
|
|
|
|
|
|
//We don't want to make the devices under us think we're still a valid provider if we have no powernet to connect to
|
2018-05-27 21:45:31 +02:00
|
|
|
|
foreach (var device in AdvertisedDevices.ToList())
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
|
|
|
|
|
device.RemoveProvider(this);
|
|
|
|
|
|
}
|
2018-08-31 08:52:48 +02:00
|
|
|
|
|
2018-05-27 21:45:31 +02:00
|
|
|
|
AdvertisedDevices.Clear();
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-05-30 16:10:36 +02:00
|
|
|
|
/// Register a continuous load from a device connected to the powernet
|
2018-02-03 22:35:42 -06:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void AddDevice(PowerDeviceComponent device)
|
|
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
DeviceLoadList.Add(device);
|
2018-08-31 08:52:48 +02:00
|
|
|
|
TheoreticalLoad += device.Load;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
if (!device.Powered)
|
|
|
|
|
|
DepoweredDevices.Add(device);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-05-30 16:10:36 +02:00
|
|
|
|
/// Update one of the loads from a deviceconnected to the powernet
|
2018-02-03 22:35:42 -06:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void UpdateDevice(PowerDeviceComponent device, float oldLoad)
|
|
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
if (DeviceLoadList.Contains(device))
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2020-02-06 08:50:52 -05:00
|
|
|
|
TheoreticalLoad = TheoreticalLoad - oldLoad + device.Load;
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-05-30 16:10:36 +02:00
|
|
|
|
/// Remove a continuous load from a device connected to the powernet
|
2018-02-03 22:35:42 -06:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void RemoveDevice(PowerDeviceComponent device)
|
|
|
|
|
|
{
|
2018-05-27 16:44:50 +02:00
|
|
|
|
if (DeviceLoadList.Contains(device))
|
2018-02-03 22:35:42 -06:00
|
|
|
|
{
|
2018-08-31 08:52:48 +02:00
|
|
|
|
TheoreticalLoad -= device.Load;
|
2018-05-27 16:44:50 +02:00
|
|
|
|
DeviceLoadList.Remove(device);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
if (DepoweredDevices.Contains(device))
|
|
|
|
|
|
DepoweredDevices.Remove(device);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2018-08-31 08:52:48 +02:00
|
|
|
|
Logger.WarningS("power", "We tried to remove device {0} twice from the same {1}, somehow.",
|
|
|
|
|
|
device.Owner, Owner);
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-09-06 10:05:17 +02:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Whether the device can be serviced by this provider.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool CanServiceDevice(PowerDeviceComponent device)
|
|
|
|
|
|
{
|
2019-09-17 16:08:45 -07:00
|
|
|
|
// Stops an APC from trying to connect to itself
|
|
|
|
|
|
if (this == device)
|
|
|
|
|
|
return false;
|
2019-09-19 13:46:01 +02:00
|
|
|
|
|
2020-02-07 08:55:27 -08:00
|
|
|
|
return device.Owner.Transform.MapID == Owner.Transform.MapID &&
|
|
|
|
|
|
(device.Owner.Transform.WorldPosition - Owner.Transform.WorldPosition).Length <= _range;
|
2019-09-06 10:05:17 +02:00
|
|
|
|
}
|
2018-02-03 22:35:42 -06:00
|
|
|
|
}
|
|
|
|
|
|
}
|