Show battery level for selected devices in Power Monitoring Console (#33854)

* Use class instead of out variables

* Show battery level in power monitoring console

* Better color contrast for battery level + localized string

* Add visualization to battery percentage

* Reverts random ChatSystem.cs whitespace change

* Address review

* Show BatteryLevel stats in child view when selecting devices

---------

Co-authored-by: Crotalus <crotalus@users.noreply.github.com>
This commit is contained in:
ArtisticRoomba
2024-12-18 16:46:36 -08:00
committed by GitHub
parent f7bf694707
commit 9de569d973
4 changed files with 127 additions and 32 deletions

View File

@@ -6,6 +6,7 @@ using Robust.Shared.Utility;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Vector4 = Robust.Shared.Maths.Vector4;
namespace Content.Client.Power; namespace Content.Client.Power;
@@ -104,6 +105,26 @@ public sealed partial class PowerMonitoringWindow
// Update power value // Update power value
// Don't use SI prefixes, just give the number in W, so that it is readily apparent which consumer is using a lot of power. // Don't use SI prefixes, just give the number in W, so that it is readily apparent which consumer is using a lot of power.
button.PowerValue.Text = Loc.GetString("power-monitoring-window-button-value", ("value", Math.Round(entry.PowerValue).ToString("N0"))); button.PowerValue.Text = Loc.GetString("power-monitoring-window-button-value", ("value", Math.Round(entry.PowerValue).ToString("N0")));
// Update battery level if applicable
if (entry.BatteryLevel != null)
{
button.BatteryLevel.Value = entry.BatteryLevel.Value;
button.BatteryLevel.Visible = true;
button.BatteryPercentage.Text = entry.BatteryLevel.Value.ToString("P0");
button.BatteryPercentage.Visible = true;
// Set progress bar color based on percentage
var color = Color.FromHsv(new Vector4(entry.BatteryLevel.Value * 0.33f, 1, 1, 1));
button.BatteryLevel.ForegroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = color };
}
else
{
button.BatteryLevel.Visible = false;
button.BatteryPercentage.Visible = false;
}
} }
private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContainer currentContainer, PowerMonitoringConsoleEntry[]? entries, SpriteSpecifier.Texture icon) private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContainer currentContainer, PowerMonitoringConsoleEntry[]? entries, SpriteSpecifier.Texture icon)
@@ -443,6 +464,11 @@ public sealed class PowerMonitoringButton : Button
public BoxContainer MainContainer; public BoxContainer MainContainer;
public TextureRect TextureRect; public TextureRect TextureRect;
public Label NameLocalized; public Label NameLocalized;
public ProgressBar BatteryLevel;
public PanelContainer BackgroundPanel;
public Label BatteryPercentage;
public Label PowerValue; public Label PowerValue;
public PowerMonitoringButton() public PowerMonitoringButton()
@@ -478,6 +504,49 @@ public sealed class PowerMonitoringButton : Button
MainContainer.AddChild(NameLocalized); MainContainer.AddChild(NameLocalized);
BatteryLevel = new ProgressBar()
{
SetWidth = 47f,
SetHeight = 20f,
Margin = new Thickness(15, 0, 0, 0),
MaxValue = 1,
Visible = false,
BackgroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = Color.Black },
};
MainContainer.AddChild(BatteryLevel);
BackgroundPanel = new PanelContainer
{
// Draw a half-transparent box over the battery level to make the text more readable.
PanelOverride = new StyleBoxFlat
{
BackgroundColor = new Color(0, 0, 0, 0.9f)
},
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
HorizontalExpand = true,
VerticalExpand = true,
// Box is undersized perfectly compared to the progress bar, so a little bit of the unaffected progress bar is visible.
SetSize = new Vector2(43f, 16f)
};
BatteryLevel.AddChild(BackgroundPanel);
BatteryPercentage = new Label()
{
VerticalAlignment = VAlignment.Center,
HorizontalAlignment = HAlignment.Center,
Align = Label.AlignMode.Center,
SetWidth = 45f,
MinWidth = 20f,
Margin = new Thickness(10, -4, 10, 0),
ClipText = true,
Visible = false,
};
BackgroundPanel.AddChild(BatteryPercentage);
PowerValue = new Label() PowerValue = new Label()
{ {
HorizontalAlignment = HAlignment.Right, HorizontalAlignment = HAlignment.Right,

View File

@@ -350,19 +350,20 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue; continue;
// Get the device power stats // Get the device power stats
var powerValue = GetPrimaryPowerValues(ent, device, out var powerSupplied, out var powerUsage, out var batteryUsage); var powerStats = GetPowerStats(ent, device);
//, out var powerSupplied, out var powerUsage, out var batteryUsage);
// Update all running totals // Update all running totals
totalSources += powerSupplied; totalSources += powerStats.PowerSupplied;
totalLoads += powerUsage; totalLoads += powerStats.PowerUsage;
totalBatteryUsage += batteryUsage; totalBatteryUsage += powerStats.BatteryUsage;
// Continue on if the device is not in the current focus group // Continue on if the device is not in the current focus group
if (device.Group != component.FocusGroup) if (device.Group != component.FocusGroup)
continue; continue;
// Generate a new console entry with which to populate the UI // Generate a new console entry with which to populate the UI
var entry = new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), device.Group, powerValue); var entry = new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), device.Group, powerStats.PowerValue, powerStats.BatteryLevel);
allEntries.Add(entry); allEntries.Add(entry);
} }
@@ -426,28 +427,28 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
loadsForFocus.ToArray())); loadsForFocus.ToArray()));
} }
private double GetPrimaryPowerValues(EntityUid uid, PowerMonitoringDeviceComponent device, out double powerSupplied, out double powerUsage, out double batteryUsage) private PowerStats GetPowerStats(EntityUid uid, PowerMonitoringDeviceComponent device)
{ {
var powerValue = 0d; var stats = new PowerStats();
powerSupplied = 0d;
powerUsage = 0d;
batteryUsage = 0d;
if (device.Group == PowerMonitoringConsoleGroup.Generator) if (device.Group == PowerMonitoringConsoleGroup.Generator)
{ {
// This covers most power sources // This covers most power sources
if (TryComp<PowerSupplierComponent>(uid, out var supplier)) if (TryComp<PowerSupplierComponent>(uid, out var supplier))
{ {
powerValue = supplier.CurrentSupply; stats.PowerValue = supplier.CurrentSupply;
powerSupplied += powerValue; stats.PowerSupplied += stats.PowerValue;
} }
// Edge case: radiation collectors // Edge case: radiation collectors
else if (TryComp<BatteryDischargerComponent>(uid, out var _) && else if (TryComp<BatteryDischargerComponent>(uid, out var _) &&
TryComp<PowerNetworkBatteryComponent>(uid, out var battery)) TryComp<PowerNetworkBatteryComponent>(uid, out var battery))
{ {
powerValue = battery.NetworkBattery.CurrentSupply; stats.PowerValue = battery.NetworkBattery.CurrentSupply;
powerSupplied += powerValue; stats.PowerSupplied += stats.PowerValue;
stats.BatteryLevel = GetBatteryLevel(uid);
} }
} }
@@ -458,18 +459,20 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
if (TryComp<PowerNetworkBatteryComponent>(uid, out var battery)) if (TryComp<PowerNetworkBatteryComponent>(uid, out var battery))
{ {
powerValue = battery.CurrentSupply; stats.BatteryLevel = GetBatteryLevel(uid);
stats.PowerValue = battery.CurrentSupply;
// Load due to network battery recharging // Load due to network battery recharging
powerUsage += Math.Max(battery.CurrentReceiving - battery.CurrentSupply, 0d); stats.PowerUsage += Math.Max(battery.CurrentReceiving - battery.CurrentSupply, 0d);
// Track battery usage // Track battery usage
batteryUsage += Math.Max(battery.CurrentSupply - battery.CurrentReceiving, 0d); stats.BatteryUsage += Math.Max(battery.CurrentSupply - battery.CurrentReceiving, 0d);
// Records loads attached to APCs // Records loads attached to APCs
if (device.Group == PowerMonitoringConsoleGroup.APC && battery.Enabled) if (device.Group == PowerMonitoringConsoleGroup.APC && battery.Enabled)
{ {
powerUsage += battery.NetworkBattery.LoadingNetworkDemand; stats.PowerUsage += battery.NetworkBattery.LoadingNetworkDemand;
} }
} }
} }
@@ -486,16 +489,28 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
if (childDevice.IsCollectionMaster && childDevice.ChildDevices.ContainsKey(uid)) if (childDevice.IsCollectionMaster && childDevice.ChildDevices.ContainsKey(uid))
continue; continue;
var childPowerValue = GetPrimaryPowerValues(child, childDevice, out var childPowerSupplied, out var childPowerUsage, out var childBatteryUsage); var childResult = GetPowerStats(child, childDevice);
powerValue += childPowerValue; stats.PowerValue += childResult.PowerValue;
powerSupplied += childPowerSupplied; stats.PowerSupplied += childResult.PowerSupplied;
powerUsage += childPowerUsage; stats.PowerUsage += childResult.PowerUsage;
batteryUsage += childBatteryUsage; stats.BatteryUsage += childResult.BatteryUsage;
} }
} }
return powerValue; return stats;
}
private float? GetBatteryLevel(EntityUid uid)
{
if (!TryComp<BatteryComponent>(uid, out var battery))
return null;
var effectiveMax = battery.MaxCharge;
if (effectiveMax == 0)
effectiveMax = 1;
return battery.CurrentCharge / effectiveMax;
} }
private void GetSourcesForNode(EntityUid uid, Node node, out List<PowerMonitoringConsoleEntry> sources) private void GetSourcesForNode(EntityUid uid, Node node, out List<PowerMonitoringConsoleEntry> sources)
@@ -532,7 +547,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue; continue;
} }
indexedSources.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, powerSupplier.CurrentSupply)); indexedSources.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, powerSupplier.CurrentSupply, GetBatteryLevel(ent)));
} }
} }
@@ -562,7 +577,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue; continue;
} }
indexedSources.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, entBattery.CurrentSupply)); indexedSources.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, entBattery.CurrentSupply, GetBatteryLevel(ent)));
} }
} }
@@ -609,7 +624,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
for (int i = 0; i < sources.Count; i++) for (int i = 0; i < sources.Count; i++)
{ {
var entry = sources[i]; var entry = sources[i];
sources[i] = new PowerMonitoringConsoleEntry(entry.NetEntity, entry.Group, entry.PowerValue * powerFraction); sources[i] = new PowerMonitoringConsoleEntry(entry.NetEntity, entry.Group, entry.PowerValue * powerFraction, entry.BatteryLevel);
} }
} }
@@ -646,7 +661,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue; continue;
} }
indexedLoads.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, powerConsumer.ReceivedPower)); indexedLoads.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, powerConsumer.ReceivedPower, GetBatteryLevel(ent)));
} }
} }
@@ -676,7 +691,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
continue; continue;
} }
indexedLoads.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, battery.CurrentReceiving)); indexedLoads.Add(ent, new PowerMonitoringConsoleEntry(EntityManager.GetNetEntity(ent), entDevice.Group, battery.CurrentReceiving, GetBatteryLevel(ent)));
} }
} }
@@ -713,7 +728,7 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
for (int i = 0; i < indexedLoads.Values.Count; i++) for (int i = 0; i < indexedLoads.Values.Count; i++)
{ {
var entry = loads[i]; var entry = loads[i];
loads[i] = new PowerMonitoringConsoleEntry(entry.NetEntity, entry.Group, entry.PowerValue * powerFraction); loads[i] = new PowerMonitoringConsoleEntry(entry.NetEntity, entry.Group, entry.PowerValue * powerFraction, entry.BatteryLevel);
} }
} }
@@ -990,4 +1005,13 @@ internal sealed partial class PowerMonitoringConsoleSystem : SharedPowerMonitori
Dirty(uid, component); Dirty(uid, component);
} }
private struct PowerStats
{
public double PowerValue { get; set; }
public double PowerSupplied { get; set; }
public double PowerUsage { get; set; }
public double BatteryUsage { get; set; }
public float? BatteryLevel { get; set; }
}
} }

View File

@@ -102,14 +102,16 @@ public struct PowerMonitoringConsoleEntry
public NetEntity NetEntity; public NetEntity NetEntity;
public PowerMonitoringConsoleGroup Group; public PowerMonitoringConsoleGroup Group;
public double PowerValue; public double PowerValue;
public float? BatteryLevel;
[NonSerialized] public PowerMonitoringDeviceMetaData? MetaData = null; [NonSerialized] public PowerMonitoringDeviceMetaData? MetaData = null;
public PowerMonitoringConsoleEntry(NetEntity netEntity, PowerMonitoringConsoleGroup group, double powerValue = 0d) public PowerMonitoringConsoleEntry(NetEntity netEntity, PowerMonitoringConsoleGroup group, double powerValue = 0d, float? batteryLevel = null)
{ {
NetEntity = netEntity; NetEntity = netEntity;
Group = group; Group = group;
PowerValue = powerValue; PowerValue = powerValue;
BatteryLevel = batteryLevel;
} }
} }

View File

@@ -22,7 +22,7 @@ power-monitoring-window-show-hv-cable = High voltage
power-monitoring-window-show-mv-cable = Medium voltage power-monitoring-window-show-mv-cable = Medium voltage
power-monitoring-window-show-lv-cable = Low voltage power-monitoring-window-show-lv-cable = Low voltage
power-monitoring-window-flavor-left = [user@nanotrasen] $run power_net_query power-monitoring-window-flavor-left = [user@nanotrasen] $run power_net_query
power-monitoring-window-flavor-right = v1.3 power-monitoring-window-flavor-right = v1.3
power-monitoring-window-rogue-power-consumer = [color=white][font size=14][bold]! WARNING - ROGUE POWER CONSUMING DEVICE DETECTED ![/bold][/font][/color] power-monitoring-window-rogue-power-consumer = [color=white][font size=14][bold]! WARNING - ROGUE POWER CONSUMING DEVICE DETECTED ![/bold][/font][/color]
power-monitoring-window-power-net-abnormalities = [color=white][font size=14][bold]CAUTION - ABNORMAL ACTIVITY IN POWER NET[/bold][/font][/color] power-monitoring-window-power-net-abnormalities = [color=white][font size=14][bold]CAUTION - ABNORMAL ACTIVITY IN POWER NET[/bold][/font][/color]