diff --git a/Content.Server/GameObjects/Components/Power/PowerDevice.cs b/Content.Server/GameObjects/Components/Power/PowerDevice.cs
index 7df5f041d6..10dcd4812e 100644
--- a/Content.Server/GameObjects/Components/Power/PowerDevice.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerDevice.cs
@@ -67,7 +67,8 @@ namespace Content.Server.GameObjects.Components.Power
private float _load = 100; //arbitrary magic number to start
///
- /// Power load from this entity
+ /// Power load from this entity.
+ /// In Watts.
///
public float Load
{
diff --git a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
index af5c810612..6c0d6a5f5d 100644
--- a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
@@ -72,18 +72,20 @@ namespace Content.Server.GameObjects.Components.Power
return;
}
- if (storage.CanDeductCharge(Load))
+
+ if (storage.CanDeductCharge(Load * frametime))
{
PowerAllDevices();
- storage.DeductCharge(Load);
+ storage.DeductCharge(Load * frametime);
return;
}
- var remainingLoad = storage.AvailableCharge();
- var usedLoad = 0f;
+ var remainingEnergy = storage.AvailableCharge(frametime);
+ var usedEnergy = 0f;
foreach (var device in DeviceLoadList)
{
- if (device.Load > remainingLoad)
+ var deviceLoad = device.Load * frametime;
+ if (deviceLoad > remainingEnergy)
{
device.ExternalPowered = false;
DepoweredDevices.Add(device);
@@ -92,15 +94,15 @@ namespace Content.Server.GameObjects.Components.Power
{
if (!device.ExternalPowered)
{
- device.ExternalPowered = true;
DepoweredDevices.Remove(device);
+ device.ExternalPowered = true;
}
- usedLoad += device.Load;
- remainingLoad -= device.Load;
+ usedEnergy += deviceLoad;
+ remainingEnergy -= deviceLoad;
}
}
- storage.DeductCharge(usedLoad);
+ storage.DeductCharge(usedEnergy);
}
private void PowerAllDevices()
{
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
index 2236351173..37aa5264d1 100644
--- a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
@@ -15,22 +15,26 @@ namespace Content.Server.GameObjects.Components.Power
public override string Name => "PowerStorage";
///
- /// Maximum amount of energy the internal battery can store
+ /// Maximum amount of energy the internal battery can store.
+ /// In Joules.
///
public float Capacity { get; private set; } = 10000; //arbitrary value replace
///
- /// Energy the battery is currently storing
+ /// Energy the battery is currently storing.
+ /// In Joules.
///
public float Charge { get; private set; } = 0;
///
- /// Rate at which energy will be taken to charge internal battery
+ /// Rate at which energy will be taken to charge internal battery.
+ /// In Watts.
///
public float ChargeRate { get; private set; } = 1000;
///
- /// Rate at which energy will be distributed to the powernet if needed
+ /// Rate at which energy will be distributed to the powernet if needed.
+ /// In Watts.
///
public float DistributionRate { get; private set; } = 1000;
@@ -124,47 +128,33 @@ namespace Content.Server.GameObjects.Components.Power
///
public void DeductCharge(float todeduct)
{
- Charge = Math.Min(0, Charge - todeduct);
+ Charge = Math.Max(0, Charge - todeduct);
}
- ///
- /// Returns all possible charge available from the energy storage
- ///
- public float RequestAllCharge()
+ public void AddCharge(float charge)
{
- return Math.Min(ChargeRate, Capacity - Charge);
+ Charge = Math.Min(Capacity, Charge + charge);
}
///
/// Returns the charge available from the energy storage
///
- public float RequestCharge()
+ public float RequestCharge(float frameTime)
{
- return Math.Min(ChargeRate, Capacity - Charge);
+ return Math.Min(ChargeRate * frameTime, Capacity - Charge);
}
///
/// Returns the charge available from the energy storage
///
- public float AvailableCharge()
+ public float AvailableCharge(float frameTime)
{
- return Math.Min(DistributionRate, Charge);
+ return Math.Min(DistributionRate * frameTime, Charge);
}
- ///
- /// Gives the storage one full tick of charging its energy storage
- ///
- public void ChargePowerTick()
+ public void ChargePowerTick(float frameTime)
{
- Charge = Math.Min(Charge + ChargeRate, Capacity);
- }
-
- ///
- /// Takes from the storage one full tick of energy
- ///
- public void RetrievePassiveStorage()
- {
- Charge = Math.Min(Charge - DistributionRate, 0);
+ AddCharge(RequestCharge(frameTime));
}
///
diff --git a/Content.Server/GameObjects/Components/Power/Powernet.cs b/Content.Server/GameObjects/Components/Power/Powernet.cs
index 7a1f429ec7..190915c52d 100644
--- a/Content.Server/GameObjects/Components/Power/Powernet.cs
+++ b/Content.Server/GameObjects/Components/Power/Powernet.cs
@@ -20,153 +20,147 @@ namespace Content.Server.GameObjects.Components.Power
Uid = powerSystem.NewUid();
}
+ ///
+ /// Unique identifier per powernet, used for debugging mostly.
+ ///
public int Uid { get; }
///
- /// The entities that make up the powernet's physical location and allow powernet connection
+ /// The entities that make up the powernet's physical location and allow powernet connection
///
- public List WireList { get; set; } = new List();
+ public readonly List WireList = new List();
///
- /// Entities that connect directly to the powernet through PTC above to add power or add power load
+ /// Entities that connect directly to the powernet through above to add power or add power load
///
- public List NodeList { get; set; } = new List();
+ public readonly List NodeList = new List();
///
- /// Subset of nodelist that adds a continuous power supply to the network
+ /// Subset of nodelist that adds a continuous power supply to the network
///
- public Dictionary GeneratorList { get; set; } = new Dictionary();
+ private readonly Dictionary GeneratorList = new Dictionary();
///
- /// Subset of nodelist that draw power, stores information on current continuous powernet load
+ /// Subset of nodelist that draw power, stores information on current continuous powernet load
///
- public SortedSet DeviceLoadList { get; set; } = new SortedSet(new DevicePriorityCompare());
+ private readonly SortedSet DeviceLoadList = new SortedSet(new DevicePriorityCompare());
///
- /// Comparer that keeps the device dictionary sorted by powernet priority
+ /// All the devices that have been depowered by this powernet or depowered prior to being absorted into this powernet
///
- public class DevicePriorityCompare : IComparer
- {
- public int Compare(PowerDeviceComponent x, PowerDeviceComponent y)
- {
- int compare = y.Priority.CompareTo(x.Priority);
-
- //If the comparer returns 0 sortedset will believe it is a duplicate and return 0, so return 1 instead
- if (compare == 0 && !x.Equals(y))
- {
- return 1;
- }
- return compare;
- }
- }
+ private readonly List DepoweredDevices = new List();
///
- /// Priority that a device will receive power if powernet cannot supply every device
+ /// A list of the energy storage components that will feed the powernet if necessary, and if there is enough power feed itself
///
- public enum Priority
- {
- Necessary,
- High,
- Medium,
- Low,
- Provider,
- Unnecessary
- }
+ private readonly List PowerStorageSupplierList = new List();
///
- /// All the devices that have been depowered by this powernet or depowered prior to being absorted into this powernet
+ /// A list of energy storage components that will never feed the powernet, will try to draw energy to feed themselves if possible
///
- public List DepoweredDevices { get; set; } = new List();
+ private readonly List PowerStorageConsumerList = new List();
///
- /// A list of the energy storage components that will feed the powernet if necessary, and if there is enough power feed itself
- ///
- public List PowerStorageSupplierlist { get; set; } = new List();
-
- ///
- /// A list of energy storage components that will never feed the powernet, will try to draw energy to feed themselves if possible
- ///
- public List PowerStorageConsumerlist { get; set; } = new List();
-
- ///
- /// Static counter of all continuous load placed from devices on this power network
+ /// Static counter of all continuous load placed from devices on this power network.
+ /// In Watts.
///
public float Load { get; private set; } = 0;
///
- /// Static counter of all continiuous supply from generators on this power network
+ /// Static counter of all continiuous supply from generators on this power network.
+ /// In Watts.
///
public float Supply { get; private set; } = 0;
///
- /// Variable that causes powernet to be regenerated from its wires during the next update cycle
+ /// Variable that causes powernet to be regenerated from its wires during the next update cycle.
///
public bool Dirty { get; set; } = false;
- public void Update(float frametime)
+ public void Update(float frameTime)
{
- float activesupply = Supply;
- float activeload = Load;
+ float activesupply = Supply * frameTime;
+ float activeload = Load * frameTime;
- float storagedemand = 0;
+ float storageconsumerdemand = 0;
- foreach (var supply in PowerStorageConsumerlist)
+ foreach (var supply in PowerStorageConsumerList)
{
- storagedemand += supply.RequestCharge();
+ storageconsumerdemand += supply.RequestCharge(frameTime);
}
- float passivesupply = 0;
- float passivedemand = 0;
+ float storagesupply = 0;
+ float storagesupplierdemand = 0;
- foreach (var supply in PowerStorageSupplierlist)
+ foreach (var supply in PowerStorageSupplierList)
{
- passivesupply += supply.AvailableCharge();
- passivedemand += supply.RequestCharge();
+ storagesupply += supply.AvailableCharge(frameTime);
+ storagesupplierdemand += supply.RequestCharge(frameTime);
}
//If we have enough power to feed all load and storage demand, then feed everything
- if (activesupply > activeload + storagedemand + passivedemand)
+ if (activesupply > activeload + storageconsumerdemand + storagesupplierdemand)
{
PowerAllDevices();
- ChargeActiveStorage();
- ChargePassiveStorage();
+ ChargeStorageConsumers(frameTime);
+ ChargeStorageSuppliers(frameTime);
+ return;
}
//We don't have enough power for the storage powernet suppliers, ignore powering them
- else if (activesupply > activeload + storagedemand)
+ else if (activesupply > activeload + storageconsumerdemand)
{
PowerAllDevices();
- ChargeActiveStorage();
+ ChargeStorageConsumers(frameTime);
+ return;
}
- //We require the storage powernet suppliers to power the remaining storage components and device load
- else if (activesupply + passivesupply > activeload + storagedemand)
- {
- PowerAllDevices();
- ChargeActiveStorage();
- RetrievePassiveStorage();
- }
- //We cant afford to fund the storage components, so lets try to power the basic load using our supply and storage supply
- else if (activesupply + passivesupply > activeload)
- {
- PowerAllDevices();
- RetrievePassiveStorage();
- }
- //We cant even cover the basic device load, start disabling devices in order of priority until the remaining load is lowered enough to be met
- else if (activesupply + passivesupply < activeload)
- {
- PowerAllDevices(); //This merely makes our inevitable betrayal all the sweeter
- RetrievePassiveStorage();
- var depowervalue = activeload - (activesupply + passivesupply);
- //Providers use same method to recreate functionality
- foreach (var device in DeviceLoadList)
+ float totalRemaining = activesupply + storagesupply;
+
+ foreach (var device in DeviceLoadList)
+ {
+ var deviceLoad = device.Load * frameTime;
+ if (deviceLoad > totalRemaining)
{
device.ExternalPowered = false;
DepoweredDevices.Add(device);
- depowervalue -= device.Load;
- if (depowervalue < 0)
- break;
+ }
+ else
+ {
+ totalRemaining -= deviceLoad;
+ if (!device.ExternalPowered)
+ {
+ DepoweredDevices.Remove(device);
+ device.ExternalPowered = true;
+ }
+ }
+ }
+
+ // What we have left goes into storage consumers.
+ foreach (var consumer in PowerStorageConsumerList)
+ {
+ if (totalRemaining < 0)
+ {
+ break;
+ }
+ var demand = consumer.RequestCharge(frameTime);
+ var taken = Math.Min(demand, totalRemaining);
+ totalRemaining -= taken;
+ consumer.AddCharge(taken);
+ }
+
+ var supplierUsed = storagesupply - totalRemaining;
+
+ foreach (var supplier in PowerStorageSupplierList)
+ {
+ var load = supplier.AvailableCharge(frameTime);
+ var added = Math.Min(load, supplierUsed);
+ supplierUsed -= added;
+ supplier.DeductCharge(added);
+ if (supplierUsed <= 0)
+ {
+ return;
}
}
}
@@ -180,27 +174,19 @@ namespace Content.Server.GameObjects.Components.Power
DepoweredDevices.Clear();
}
- private void ChargeActiveStorage()
+ private void ChargeStorageConsumers(float frametime)
{
- foreach (var storage in PowerStorageConsumerlist)
+ foreach (var storage in PowerStorageConsumerList)
{
- storage.ChargePowerTick();
+ storage.ChargePowerTick(frametime);
}
}
- private void ChargePassiveStorage()
+ private void ChargeStorageSuppliers(float frametime)
{
- foreach (var storage in PowerStorageSupplierlist)
+ foreach (var storage in PowerStorageSupplierList)
{
- storage.ChargePowerTick();
- }
- }
-
- private void RetrievePassiveStorage()
- {
- foreach (var storage in PowerStorageSupplierlist)
- {
- storage.ChargePowerTick();
+ storage.ChargePowerTick(frametime);
}
}
@@ -217,8 +203,8 @@ namespace Content.Server.GameObjects.Components.Power
GeneratorList.Clear();
DeviceLoadList.Clear();
DepoweredDevices.Clear();
- PowerStorageSupplierlist.Clear();
- PowerStorageConsumerlist.Clear();
+ PowerStorageSupplierList.Clear();
+ PowerStorageConsumerList.Clear();
RemoveFromSystem();
}
@@ -259,11 +245,11 @@ namespace Content.Server.GameObjects.Components.Power
DepoweredDevices.AddRange(toMerge.DepoweredDevices);
toMerge.DepoweredDevices.Clear();
- PowerStorageSupplierlist.AddRange(toMerge.PowerStorageSupplierlist);
- toMerge.PowerStorageSupplierlist.Clear();
+ PowerStorageSupplierList.AddRange(toMerge.PowerStorageSupplierList);
+ toMerge.PowerStorageSupplierList.Clear();
- PowerStorageConsumerlist.AddRange(toMerge.PowerStorageConsumerlist);
- toMerge.PowerStorageConsumerlist.Clear();
+ PowerStorageConsumerList.AddRange(toMerge.PowerStorageConsumerList);
+ toMerge.PowerStorageConsumerList.Clear();
toMerge.RemoveFromSystem();
}
@@ -366,25 +352,25 @@ namespace Content.Server.GameObjects.Components.Power
public void AddPowerStorage(PowerStorageComponent storage)
{
if (storage.ChargePowernet)
- PowerStorageSupplierlist.Add(storage);
+ PowerStorageSupplierList.Add(storage);
else
- PowerStorageConsumerlist.Add(storage);
+ PowerStorageConsumerList.Add(storage);
}
//How do I even call this? TODO: fix
public void UpdateStorageType(PowerStorageComponent storage)
{
//If our chargepowernet settings change we need to tell the powernet of this new setting and remove traces of our old setting
- if (PowerStorageSupplierlist.Contains(storage))
- PowerStorageSupplierlist.Remove(storage);
- if (PowerStorageConsumerlist.Contains(storage))
- PowerStorageConsumerlist.Remove(storage);
+ if (PowerStorageSupplierList.Contains(storage))
+ PowerStorageSupplierList.Remove(storage);
+ if (PowerStorageConsumerList.Contains(storage))
+ PowerStorageConsumerList.Remove(storage);
//Apply new setting
if (storage.ChargePowernet)
- PowerStorageSupplierlist.Add(storage);
+ PowerStorageSupplierList.Add(storage);
else
- PowerStorageConsumerlist.Add(storage);
+ PowerStorageConsumerList.Add(storage);
}
///
@@ -392,15 +378,46 @@ namespace Content.Server.GameObjects.Components.Power
///
public void RemovePowerStorage(PowerStorageComponent storage)
{
- if (PowerStorageSupplierlist.Contains(storage))
+ if (PowerStorageSupplierList.Contains(storage))
{
- PowerStorageSupplierlist.Remove(storage);
+ PowerStorageSupplierList.Remove(storage);
}
- if (PowerStorageConsumerlist.Contains(storage))
+ if (PowerStorageConsumerList.Contains(storage))
{
- PowerStorageSupplierlist.Remove(storage);
+ PowerStorageSupplierList.Remove(storage);
}
}
#endregion Registration
+
+ ///
+ /// Priority that a device will receive power if powernet cannot supply every device
+ ///
+ public enum Priority
+ {
+ Necessary,
+ High,
+ Medium,
+ Low,
+ Provider,
+ Unnecessary
+ }
+
+ ///
+ /// Comparer that keeps the device dictionary sorted by powernet priority
+ ///
+ public class DevicePriorityCompare : IComparer
+ {
+ public int Compare(PowerDeviceComponent x, PowerDeviceComponent y)
+ {
+ int compare = y.Priority.CompareTo(x.Priority);
+
+ //If the comparer returns 0 sortedset will believe it is a duplicate and return 0, so return 1 instead
+ if (compare == 0 && !x.Equals(y))
+ {
+ return 1;
+ }
+ return compare;
+ }
+ }
}
}