Files
ss14-wl/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs
slarticodefast e2ff167062 Predict powercells, chargers and PowerCellDraw (#41379)
* cleanup

* fix fixtures

* prediction

* fix test

* review

* fix svalinn visuals

* fix chargers

* fix portable recharger and its unlit visuals

* fix borgs

* oomba review

* fix examination prediction
2025-11-24 16:52:11 +00:00

164 lines
6.0 KiB
C#

using System.Linq;
using Content.Shared.UserInterface;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.NameIdentifier;
using Content.Shared.PowerCell.Components;
using Content.Shared.Preferences;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Shared.Configuration;
namespace Content.Server.Silicons.Borgs;
/// <inheritdoc/>
public sealed partial class BorgSystem
{
// CCvar.
private int _maxNameLength;
public void InitializeUI()
{
SubscribeLocalEvent<BorgChassisComponent, BeforeActivatableUIOpenEvent>(OnBeforeBorgUiOpen);
SubscribeLocalEvent<BorgChassisComponent, BorgEjectBrainBuiMessage>(OnEjectBrainBuiMessage);
SubscribeLocalEvent<BorgChassisComponent, BorgEjectBatteryBuiMessage>(OnEjectBatteryBuiMessage);
SubscribeLocalEvent<BorgChassisComponent, BorgSetNameBuiMessage>(OnSetNameBuiMessage);
SubscribeLocalEvent<BorgChassisComponent, BorgRemoveModuleBuiMessage>(OnRemoveModuleBuiMessage);
Subs.CVar(_cfgManager, CCVars.MaxNameLength, value => _maxNameLength = value, true);
}
private void OnBeforeBorgUiOpen(EntityUid uid, BorgChassisComponent component, BeforeActivatableUIOpenEvent args)
{
UpdateUI(uid, component);
}
private void OnEjectBrainBuiMessage(EntityUid uid, BorgChassisComponent component, BorgEjectBrainBuiMessage args)
{
if (component.BrainEntity is not { } brain)
return;
_adminLog.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(args.Actor):player} removed brain {ToPrettyString(brain)} from borg {ToPrettyString(uid)}");
_container.Remove(brain, component.BrainContainer);
_hands.TryPickupAnyHand(args.Actor, brain);
UpdateUI(uid, component);
}
private void OnEjectBatteryBuiMessage(EntityUid uid, BorgChassisComponent component, BorgEjectBatteryBuiMessage args)
{
if (TryEjectPowerCell(uid, component, out var ents))
_hands.TryPickupAnyHand(args.Actor, ents.First());
}
private void OnSetNameBuiMessage(EntityUid uid, BorgChassisComponent component, BorgSetNameBuiMessage args)
{
if (args.Name.Length > _maxNameLength ||
args.Name.Length == 0 ||
string.IsNullOrWhiteSpace(args.Name) ||
string.IsNullOrEmpty(args.Name))
{
return;
}
var name = args.Name.Trim();
var metaData = MetaData(uid);
// don't change the name if the value doesn't actually change
if (metaData.EntityName.Equals(name, StringComparison.InvariantCulture))
return;
_adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} set borg \"{ToPrettyString(uid)}\"'s name to: {name}");
_metaData.SetEntityName(uid, name, metaData);
}
private void OnRemoveModuleBuiMessage(EntityUid uid, BorgChassisComponent component, BorgRemoveModuleBuiMessage args)
{
var module = GetEntity(args.Module);
if (!component.ModuleContainer.Contains(module))
return;
if (!CanRemoveModule((uid, component), (module, Comp<BorgModuleComponent>(module)), args.Actor))
return;
_adminLog.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(args.Actor):player} removed module {ToPrettyString(module)} from borg {ToPrettyString(uid)}");
_container.Remove(module, component.ModuleContainer);
_hands.TryPickupAnyHand(args.Actor, module);
UpdateUI(uid, component);
}
public void UpdateBattery(Entity<BorgChassisComponent> ent)
{
UpdateBatteryAlert(ent);
// if we aren't drawing and suddenly get enough power to draw again, reeanble.
if (_powerCell.HasDrawCharge(ent.Owner))
{
Toggle.TryActivate(ent.Owner);
}
UpdateUI(ent, ent);
}
// TODO: Move to client so we don't have to network this periodically.
private void UpdateBatteryAlert(Entity<BorgChassisComponent> ent, PowerCellSlotComponent? slotComponent = null)
{
if (!_powerCell.TryGetBatteryFromSlot((ent.Owner, slotComponent), out var battery))
{
_alerts.ClearAlert(ent.Owner, ent.Comp.BatteryAlert);
_alerts.ShowAlert(ent.Owner, ent.Comp.NoBatteryAlert);
return;
}
var chargePercent = (short)MathF.Round(_battery.GetCharge(battery.Value.AsNullable()) / battery.Value.Comp.MaxCharge * 10f);
// we make sure 0 only shows if they have absolutely no battery.
// also account for floating point imprecision
if (chargePercent == 0 && _powerCell.HasDrawCharge((ent.Owner, null, slotComponent)))
{
chargePercent = 1;
}
_alerts.ClearAlert(ent.Owner, ent.Comp.NoBatteryAlert);
_alerts.ShowAlert(ent.Owner, ent.Comp.BatteryAlert, chargePercent);
}
// TODO: Component states and update this on the client
public void UpdateUI(EntityUid uid, BorgChassisComponent? component = null)
{
if (!Resolve(uid, ref component))
return;
var chargePercent = 0f;
var hasBattery = false;
if (_powerCell.TryGetBatteryFromSlot(uid, out var battery))
{
hasBattery = true;
chargePercent = _battery.GetCharge(battery.Value.AsNullable()) / battery.Value.Comp.MaxCharge;
}
var state = new BorgBuiState(chargePercent, hasBattery);
_ui.SetUiState(uid, BorgUiKey.Key, state);
}
// periodically update the charge indicator
// TODO: Move this to the client.
public void UpdateBattery(float frameTime)
{
var curTime = _timing.CurTime;
var query = EntityQueryEnumerator<BorgChassisComponent>();
while (query.MoveNext(out var uid, out var borgChassis))
{
if (curTime < borgChassis.NextBatteryUpdate)
continue;
UpdateBattery((uid, borgChassis));
borgChassis.NextBatteryUpdate = curTime + TimeSpan.FromSeconds(1);
}
}
}