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:
@@ -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) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||
@@ -18,7 +18,11 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
|
||||
void RemoveReceiver(PowerReceiverComponent receiver);
|
||||
|
||||
void UpdateReceiverLoad(int oldLoad, int newLoad);
|
||||
|
||||
public IEntity ProviderOwner { get; }
|
||||
|
||||
public bool HasApcPower { get; }
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
@@ -28,6 +32,9 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
|
||||
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>
|
||||
@@ -49,14 +56,23 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
|
||||
public void AddReceiver(PowerReceiverComponent receiver)
|
||||
{
|
||||
var oldLoad = GetTotalLoad();
|
||||
_linkedReceivers.Add(receiver);
|
||||
Net.UpdatePowerProviderReceivers(this);
|
||||
var newLoad = oldLoad + receiver.Load;
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
public void RemoveReceiver(PowerReceiverComponent receiver)
|
||||
{
|
||||
var oldLoad = GetTotalLoad();
|
||||
_linkedReceivers.Remove(receiver);
|
||||
Net.UpdatePowerProviderReceivers(this);
|
||||
var newLoad = oldLoad - receiver.Load;
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
public void UpdateReceiverLoad(int oldLoad, int newLoad)
|
||||
{
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
@@ -82,8 +98,6 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
{
|
||||
receiver.ClearProvider();
|
||||
}
|
||||
_linkedReceivers = new List<PowerReceiverComponent>();
|
||||
Net.UpdatePowerProviderReceivers(this);
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
receiver.TryFindAndSetProvider();
|
||||
@@ -115,19 +129,37 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
|
||||
private void SetPowerTransferRange(int newPowerTransferRange)
|
||||
{
|
||||
var oldLoad = GetTotalLoad();
|
||||
foreach (var receiver in _linkedReceivers.ToArray())
|
||||
{
|
||||
receiver.ClearProvider();
|
||||
}
|
||||
_powerTransferRange = newPowerTransferRange;
|
||||
_linkedReceivers = FindAvailableReceivers();
|
||||
Net.UpdatePowerProviderReceivers(this);
|
||||
var newLoad = GetTotalLoad();
|
||||
Net.UpdatePowerProviderReceivers(this, oldLoad, newLoad);
|
||||
}
|
||||
|
||||
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,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.NodeContainer;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||
@@ -34,9 +34,11 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
[ViewVariables]
|
||||
public bool Powered => (HasApcPower || !NeedsPower) && !PowerDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// If this is being powered by an Apc.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool HasApcPower { get => _hasApcPower; set => SetHasApcPower(value); }
|
||||
private bool _hasApcPower;
|
||||
public bool HasApcPower { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The max distance from a <see cref="PowerProviderComponent"/> that this can receive power from.
|
||||
@@ -103,7 +105,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
public override void OnRemove()
|
||||
{
|
||||
if (_physicsComponent != null)
|
||||
{
|
||||
@@ -121,6 +123,14 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
}
|
||||
}
|
||||
|
||||
public void ApcPowerChanged()
|
||||
{
|
||||
var oldPowered = Powered;
|
||||
HasApcPower = Provider.HasApcPower;
|
||||
if (Powered != oldPowered)
|
||||
OnNewPowerState();
|
||||
}
|
||||
|
||||
private bool TryFindAvailableProvider(out IPowerProvider foundProvider)
|
||||
{
|
||||
var nearbyEntities = _serverEntityManager
|
||||
@@ -152,7 +162,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
_provider.RemoveReceiver(this);
|
||||
_provider = PowerProviderComponent.NullProvider;
|
||||
NeedsProvider = true;
|
||||
HasApcPower = false;
|
||||
ApcPowerChanged();
|
||||
}
|
||||
|
||||
private void SetProvider(IPowerProvider newProvider)
|
||||
@@ -161,16 +171,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
_provider = newProvider;
|
||||
newProvider.AddReceiver(this);
|
||||
NeedsProvider = false;
|
||||
}
|
||||
|
||||
private void SetHasApcPower(bool newHasApcPower)
|
||||
{
|
||||
var oldPowered = Powered;
|
||||
_hasApcPower = newHasApcPower;
|
||||
if (oldPowered != Powered)
|
||||
{
|
||||
OnNewPowerState();
|
||||
}
|
||||
ApcPowerChanged();
|
||||
}
|
||||
|
||||
private void SetPowerReceptionRange(int newPowerReceptionRange)
|
||||
@@ -182,6 +183,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
|
||||
private void SetLoad(int newLoad)
|
||||
{
|
||||
Provider.UpdateReceiverLoad(Load, newLoad);
|
||||
_load = newLoad;
|
||||
}
|
||||
|
||||
@@ -228,10 +230,10 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||
ClearProvider();
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Adds some markup to the examine text of whatever object is using this component to tell you if it's powered or not, even if it doesn't have an icon state to do this for you.
|
||||
///</summary>
|
||||
|
||||
public void Examine(FormattedMessage message, bool inDetailsRange)
|
||||
{
|
||||
message.AddMarkup(Loc.GetString("It appears to be {0}.", Powered ? "[color=darkgreen]powered[/color]" : "[color=darkred]un-powered[/color]"));
|
||||
|
||||
Reference in New Issue
Block a user