ApcNet code improvements (#2876)

* Removes per-frame setting of PowerReceiverComponent.Powered

* PowerReceiver.SetLoad

Co-authored-by: py01 <pyronetics01@gmail.com>
This commit is contained in:
py01
2021-01-01 11:21:18 -06:00
committed by GitHub
parent 4316e2f554
commit 135a65f030
3 changed files with 135 additions and 63 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Content.Server.GameObjects.Components.Power;
@@ -9,6 +10,8 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
{
public interface IApcNet
{
bool Powered { get; }
void AddApc(ApcComponent apc);
void RemoveApc(ApcComponent apc);
@@ -17,7 +20,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
void RemovePowerProvider(PowerProviderComponent provider);
void UpdatePowerProviderReceivers(PowerProviderComponent provider);
void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad);
void Update(float frameTime);
}
@@ -29,11 +32,19 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
private readonly Dictionary<ApcComponent, BatteryComponent> _apcBatteries = new();
[ViewVariables]
private readonly Dictionary<PowerProviderComponent, List<PowerReceiverComponent>> _providerReceivers = new();
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 => _providerReceivers.SelectMany(kvp => kvp.Value).Count();
private int TotalReceivers => _providers.SelectMany(provider => provider.LinkedReceivers).Count();
[ViewVariables]
private int TotalPowerReceiverLoad { get => _totalPowerReceiverLoad; set => SetTotalPowerReceiverLoad(value); }
private int _totalPowerReceiverLoad = 0;
public static readonly IApcNet NullNet = new NullApcNet();
@@ -57,80 +68,107 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
public void RemoveApc(ApcComponent apc)
{
_apcBatteries.Remove(apc);
if (!_apcBatteries.Any())
{
foreach (var receiver in _providerReceivers.SelectMany(kvp => kvp.Value))
{
receiver.HasApcPower = false;
}
}
}
public void AddPowerProvider(PowerProviderComponent provider)
{
_providerReceivers.Add(provider, provider.LinkedReceivers.ToList());
_providers.Add(provider);
foreach (var receiver in provider.LinkedReceivers)
{
TotalPowerReceiverLoad += receiver.Load;
}
}
public void RemovePowerProvider(PowerProviderComponent provider)
{
_providerReceivers.Remove(provider);
_providers.Remove(provider);
foreach (var receiver in provider.LinkedReceivers)
{
TotalPowerReceiverLoad -= receiver.Load;
}
}
public void UpdatePowerProviderReceivers(PowerProviderComponent provider)
public void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad)
{
Debug.Assert(_providerReceivers.ContainsKey(provider));
_providerReceivers[provider] = provider.LinkedReceivers.ToList();
}
Debug.Assert(_providers.Contains(provider));
TotalPowerReceiverLoad -= oldLoad;
TotalPowerReceiverLoad += newLoad;
}
public void Update(float frameTime)
{
var totalCharge = 0.0;
var totalMaxCharge = 0;
foreach (var (apc, battery) in _apcBatteries)
var remainingPowerNeeded = TotalPowerReceiverLoad * frameTime;
foreach (var apcBatteryPair in _apcBatteries)
{
var apc = apcBatteryPair.Key;
if (!apc.MainBreakerEnabled)
continue;
totalCharge += battery.CurrentCharge;
totalMaxCharge += battery.MaxCharge;
var battery = apcBatteryPair.Value;
if (battery.CurrentCharge < remainingPowerNeeded)
{
remainingPowerNeeded -= battery.CurrentCharge;
battery.CurrentCharge = 0;
}
else
{
battery.UseCharge(remainingPowerNeeded);
remainingPowerNeeded = 0;
}
if (remainingPowerNeeded == 0)
break;
}
foreach (var (_, receivers) in _providerReceivers)
{
foreach (var receiver in receivers)
{
if (!receiver.NeedsPower || receiver.PowerDisabled)
continue;
Powered = remainingPowerNeeded == 0;
}
receiver.HasApcPower = TryUsePower(receiver.Load * frameTime);
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 bool TryUsePower(float neededCharge)
private void SetTotalPowerReceiverLoad(int totalPowerReceiverLoad)
{
foreach (var (apc, battery) in _apcBatteries)
{
if (!apc.MainBreakerEnabled)
continue;
Debug.Assert(totalPowerReceiverLoad >= 0);
_totalPowerReceiverLoad = totalPowerReceiverLoad;
if (battery.TryUseCharge(neededCharge)) //simplification - all power needed must come from one battery
{
return true;
}
}
return false;
}
#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 void AddApc(ApcComponent apc) { }
public void AddPowerProvider(PowerProviderComponent provider) { }
public void RemoveApc(ApcComponent apc) { }
public void RemovePowerProvider(PowerProviderComponent provider) { }
public void UpdatePowerProviderReceivers(PowerProviderComponent provider) { }
public void UpdatePowerProviderReceivers(PowerProviderComponent provider, int oldLoad, int newLoad) { }
public void Update(float frameTime) { }
}
}