Files
tbd-station-14/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs
Pieter-Jan Briers 123a4147de BUI bugfixes / improvements (#23881)
* Fix ActivatableUIRequiresPowerCellComponent stopping power draw when one of two people closes the UI.

Also fixes it to check UiKey properly.

* Remove unnecessary CrewManifestViewer on PDAs

This is for a pop-up crew manifest UI, which the PDA doesn't use.

* Fix BoundUIClosedEvents that didn't check UI key/not correctly at least.

Uses the new helper method in engine.

* Fix drone (cargo shuttle) pilot console UI breaking if two people open it and one person closes it.

* Fixes for disposal router/tagger UI.

Code was badly copy pasted without changing identifiers, never worked.

Also cleaned up some of the logic (text trimming, sounds).

Also removed the "refuse to work if you have something in your active hand" check like why.

* Avoid running most ActivatableUIComponent logic when closing a UI via toggle

Activating the UI while it's already open closes it via toggle. Except it still ran 99% of the "attempting to open" logic which makes no sense.

This probably fixes a bug or some other dumb behavior somewhere.

* Bitch
2024-01-14 18:18:39 +11:00

817 lines
35 KiB
C#

using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.DeviceLinking.Systems;
using Content.Server.DeviceNetwork.Components;
using Content.Server.UserInterface;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Database;
using Content.Shared.DeviceLinking;
using Content.Shared.DeviceNetwork;
using Content.Shared.DeviceNetwork.Components;
using Content.Shared.DeviceNetwork.Systems;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.DeviceNetwork.Systems;
[UsedImplicitly]
public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
{
[Dependency] private readonly DeviceListSystem _deviceListSystem = default!;
[Dependency] private readonly DeviceLinkSystem _deviceLinkSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly AccessReaderSystem _accessSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NetworkConfiguratorComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<NetworkConfiguratorComponent, ComponentShutdown>(OnShutdown);
//Interaction
SubscribeLocalEvent<NetworkConfiguratorComponent, AfterInteractEvent>(AfterInteract); //TODO: Replace with utility verb?
SubscribeLocalEvent<NetworkConfiguratorComponent, ExaminedEvent>(DoExamine);
//Verbs
SubscribeLocalEvent<NetworkConfiguratorComponent, GetVerbsEvent<UtilityVerb>>(OnAddInteractVerb);
SubscribeLocalEvent<DeviceNetworkComponent, GetVerbsEvent<AlternativeVerb>>(OnAddAlternativeSaveDeviceVerb);
SubscribeLocalEvent<NetworkConfiguratorComponent, GetVerbsEvent<AlternativeVerb>>(OnAddSwitchModeVerb);
//UI
SubscribeLocalEvent<NetworkConfiguratorComponent, BoundUIClosedEvent>(OnUiClosed);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorRemoveDeviceMessage>(OnRemoveDevice);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorClearDevicesMessage>(OnClearDevice);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorLinksSaveMessage>(OnSaveLinks);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorClearLinksMessage>(OnClearLinks);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorToggleLinkMessage>(OnToggleLinks);
SubscribeLocalEvent<NetworkConfiguratorComponent, NetworkConfiguratorButtonPressedMessage>(OnConfigButtonPressed);
SubscribeLocalEvent<NetworkConfiguratorComponent, ActivatableUIOpenAttemptEvent>(OnUiOpenAttempt);
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
}
private void OnShutdown(EntityUid uid, NetworkConfiguratorComponent component, ComponentShutdown args)
{
ClearDevices(uid, component);
if (TryComp(component.ActiveDeviceList, out DeviceListComponent? list))
list.Configurators.Remove(uid);
component.ActiveDeviceList = null;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<NetworkConfiguratorComponent>();
while (query.MoveNext(out var uid, out var component))
{
if (component.ActiveDeviceList != null
&& EntityManager.EntityExists(component.ActiveDeviceList.Value)
&& _interactionSystem.InRangeUnobstructed(uid, component.ActiveDeviceList.Value))
continue;
//The network configurator is a handheld device. There can only ever be an ui session open for the player holding the device.
_uiSystem.TryCloseAll(uid, NetworkConfiguratorUiKey.Configure);
}
}
private void OnMapInit(EntityUid uid, NetworkConfiguratorComponent component, MapInitEvent args)
{
UpdateListUiState(uid, component);
}
private void TryAddNetworkDevice(EntityUid? targetUid, EntityUid configuratorUid, EntityUid userUid,
NetworkConfiguratorComponent? configurator = null)
{
if (!Resolve(configuratorUid, ref configurator))
return;
TryAddNetworkDevice(configuratorUid, targetUid, userUid, configurator);
}
private void TryAddNetworkDevice(EntityUid configuratorUid, EntityUid? targetUid, EntityUid userUid, NetworkConfiguratorComponent configurator, DeviceNetworkComponent? device = null)
{
if (!targetUid.HasValue || !Resolve(targetUid.Value, ref device, false))
return;
var address = device.Address;
if (string.IsNullOrEmpty(address))
{
// This primarily checks if the entity in question is pre-map init or not.
// This is because otherwise, anything that uses DeviceNetwork will not
// have an address populated, as all devices that use DeviceNetwork
// obtain their address on map init. If the entity is post-map init,
// and it still doesn't have an address, it will fail. Otherwise,
// it stores the entity's UID as a string for visual effect, that way
// a mapper can reference the devices they've gathered by UID, instead of
// by device network address. These entries, if the multitool is still in
// the map after it being saved, are cleared upon mapinit.
if (MetaData(targetUid.Value).EntityLifeStage == EntityLifeStage.MapInitialized)
{
_popupSystem.PopupCursor(Loc.GetString("network-configurator-device-failed", ("device", targetUid)),
userUid);
return;
}
address = $"UID: {targetUid.Value}";
}
if (configurator.Devices.ContainsValue(targetUid.Value))
{
_popupSystem.PopupCursor(Loc.GetString("network-configurator-device-already-saved", ("device", targetUid)), userUid);
return;
}
device.Configurators.Add(configuratorUid);
configurator.Devices.Add(address, targetUid.Value);
_popupSystem.PopupCursor(Loc.GetString("network-configurator-device-saved", ("address", device.Address), ("device", targetUid)),
userUid, PopupType.Medium);
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, $"{ToPrettyString(userUid):actor} saved {ToPrettyString(targetUid.Value):subject} to {ToPrettyString(configuratorUid):tool}");
UpdateListUiState(configuratorUid, configurator);
}
private void TryLinkDevice(EntityUid uid, NetworkConfiguratorComponent configurator, EntityUid? target, EntityUid user)
{
if (!HasComp<DeviceLinkSourceComponent>(target) && !HasComp<DeviceLinkSinkComponent>(target))
return;
if (configurator.ActiveDeviceLink == target)
{
_popupSystem.PopupEntity(Loc.GetString("network-configurator-link-mode-stopped"), target.Value, user);
configurator.ActiveDeviceLink = null;
return;
}
if (configurator.ActiveDeviceLink.HasValue
&& (HasComp<DeviceLinkSourceComponent>(target)
&& HasComp<DeviceLinkSinkComponent>(configurator.ActiveDeviceLink)
|| HasComp<DeviceLinkSinkComponent>(target)
&& HasComp<DeviceLinkSourceComponent>(configurator.ActiveDeviceLink)))
{
OpenDeviceLinkUi(uid, target, user, configurator);
return;
}
if (HasComp<DeviceLinkSourceComponent>(target) && HasComp<DeviceLinkSourceComponent>(configurator.ActiveDeviceLink)
|| HasComp<DeviceLinkSinkComponent>(target) && HasComp<DeviceLinkSinkComponent>(configurator.ActiveDeviceLink))
return;
_popupSystem.PopupEntity(Loc.GetString("network-configurator-link-mode-started", ("device", Name(target.Value))), target.Value, user);
configurator.ActiveDeviceLink = target;
}
private void TryLinkDefaults(EntityUid _, NetworkConfiguratorComponent configurator, EntityUid? targetUid, EntityUid user)
{
if (!configurator.LinkModeActive || !configurator.ActiveDeviceLink.HasValue
|| !targetUid.HasValue || configurator.ActiveDeviceLink == targetUid)
return;
if (!HasComp<DeviceLinkSourceComponent>(targetUid) && !HasComp<DeviceLinkSinkComponent>(targetUid))
return;
if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(targetUid, out DeviceLinkSinkComponent? targetSink))
{
_deviceLinkSystem.LinkDefaults(user, configurator.ActiveDeviceLink.Value, targetUid.Value, activeSource, targetSink);
}
else if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink) && TryComp(targetUid, out DeviceLinkSourceComponent? targetSource))
{
_deviceLinkSystem.LinkDefaults(user, targetUid.Value, configurator.ActiveDeviceLink.Value, targetSource, activeSink);
}
}
private bool AccessCheck(EntityUid target, EntityUid? user, NetworkConfiguratorComponent component)
{
if (!TryComp(target, out AccessReaderComponent? reader) || user == null)
return true;
if (_accessSystem.IsAllowed(user.Value, target, reader))
return true;
_audioSystem.PlayPvs(component.SoundNoAccess, user.Value, AudioParams.Default.WithVolume(-2f).WithPitchScale(1.2f));
_popupSystem.PopupEntity(Loc.GetString("network-configurator-device-access-denied"), target, user.Value);
return false;
}
private void OnComponentRemoved(EntityUid uid, DeviceListComponent component, ComponentRemove args)
{
_uiSystem.TryCloseAll(uid, NetworkConfiguratorUiKey.Configure);
}
/// <summary>
/// Toggles between linking and listing mode
/// </summary>
private void SwitchMode(EntityUid? userUid, EntityUid configuratorUid, NetworkConfiguratorComponent configurator)
{
if (Delay(configurator))
return;
configurator.LinkModeActive = !configurator.LinkModeActive;
if (!userUid.HasValue)
return;
if (!configurator.LinkModeActive)
configurator.ActiveDeviceLink = null;
UpdateModeAppearance(userUid.Value, configuratorUid, configurator);
}
/// <summary>
/// Sets the mode to linking or list depending on the link mode parameter
/// </summary>>
private void SetMode(EntityUid configuratorUid, NetworkConfiguratorComponent configurator, EntityUid userUid, bool linkMode)
{
configurator.LinkModeActive = linkMode;
if (!linkMode)
configurator.ActiveDeviceLink = null;
UpdateModeAppearance(userUid, configuratorUid, configurator);
}
/// <summary>
/// Updates the configurators appearance and plays a sound indicating that the mode switched
/// </summary>
private void UpdateModeAppearance(EntityUid userUid, EntityUid configuratorUid, NetworkConfiguratorComponent configurator)
{
Dirty(configurator);
_appearanceSystem.SetData(configuratorUid, NetworkConfiguratorVisuals.Mode, configurator.LinkModeActive);
var pitch = configurator.LinkModeActive ? 1 : 0.8f;
_audioSystem.PlayPvs(configurator.SoundSwitchMode, userUid, AudioParams.Default.WithVolume(1.5f).WithPitchScale(pitch));
}
/// <summary>
/// Returns true if the last time this method was called is earlier than the configurators use delay.
/// </summary>
private bool Delay(NetworkConfiguratorComponent configurator)
{
var currentTime = _gameTiming.CurTime;
if (currentTime < configurator.LastUseAttempt + configurator.UseDelay)
return true;
configurator.LastUseAttempt = currentTime;
return false;
}
#region Interactions
private void DoExamine(EntityUid uid, NetworkConfiguratorComponent component, ExaminedEvent args)
{
var mode = component.LinkModeActive ? "network-configurator-examine-mode-link" : "network-configurator-examine-mode-list";
args.PushMarkup(Loc.GetString("network-configurator-examine-current-mode", ("mode", Loc.GetString(mode))));
}
private void AfterInteract(EntityUid uid, NetworkConfiguratorComponent component, AfterInteractEvent args)
{
OnUsed(uid, component, args.Target, args.User, args.CanReach);
}
/// <summary>
/// Either adds a device to the device list or shows the config ui if the target is ant entity with a device list
/// </summary>
private void OnUsed(EntityUid uid, NetworkConfiguratorComponent configurator, EntityUid? target, EntityUid user, bool canReach = true)
{
if (!canReach || !target.HasValue)
return;
DetermineMode(uid, configurator, target, user);
if (configurator.LinkModeActive)
{
TryLinkDevice(uid, configurator, target, user);
return;
}
if (!HasComp<DeviceListComponent>(target))
{
TryAddNetworkDevice(uid, target, user, configurator);
return;
}
OpenDeviceListUi(uid, target, user, configurator);
}
private void DetermineMode(EntityUid configuratorUid, NetworkConfiguratorComponent configurator, EntityUid? target, EntityUid userUid)
{
var hasLinking = HasComp<DeviceLinkSinkComponent>(target) || HasComp<DeviceLinkSourceComponent>(target);
if (hasLinking && HasComp<DeviceListComponent>(target) || hasLinking == configurator.LinkModeActive)
return;
if (hasLinking)
{
SetMode(configuratorUid, configurator, userUid, true);
return;
}
if (HasComp<DeviceNetworkComponent>(target))
SetMode(configuratorUid, configurator, userUid, false);
}
#endregion
#region Verbs
/// <summary>
/// Adds the interaction verb which is either configuring device lists or saving a device onto the configurator
/// </summary>
private void OnAddInteractVerb(EntityUid uid, NetworkConfiguratorComponent configurator, GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue)
return;
var verb = new UtilityVerb
{
Act = () => OnUsed(uid, configurator, args.Target, args.User),
Impact = LogImpact.Low
};
if (configurator.LinkModeActive && (HasComp<DeviceLinkSinkComponent>(args.Target) || HasComp<DeviceLinkSourceComponent>(args.Target)))
{
var linkStarted = configurator.ActiveDeviceLink.HasValue;
verb.Text = Loc.GetString(linkStarted ? "network-configurator-link" : "network-configurator-start-link");
verb.Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/in.svg.192dpi.png"));
args.Verbs.Add(verb);
}
else if (HasComp<DeviceNetworkComponent>(args.Target))
{
var isDeviceList = HasComp<DeviceListComponent>(args.Target);
verb.Text = Loc.GetString(isDeviceList ? "network-configurator-configure" : "network-configurator-save-device");
verb.Icon = isDeviceList
? new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/settings.svg.192dpi.png"))
: new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/in.svg.192dpi.png"));
args.Verbs.Add(verb);
}
}
/// <summary>
/// Powerful. Funny alt interact using.
/// Adds an alternative verb for saving a device on the configurator for entities with the <see cref="DeviceListComponent"/>.
/// Allows alt clicking entities with a network configurator that would otherwise trigger a different action like entities
/// with a <see cref="DeviceListComponent"/>
/// </summary>
private void OnAddAlternativeSaveDeviceVerb(EntityUid uid, DeviceNetworkComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue
|| !TryComp<NetworkConfiguratorComponent>(args.Using.Value, out var configurator))
return;
if (!configurator.LinkModeActive && HasComp<DeviceListComponent>(args.Target))
{
AlternativeVerb verb = new()
{
Text = Loc.GetString("network-configurator-save-device"),
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/in.svg.192dpi.png")),
Act = () => TryAddNetworkDevice(args.Target, args.Using.Value, args.User),
Impact = LogImpact.Low
};
args.Verbs.Add(verb);
return;
}
if (configurator is { LinkModeActive: true, ActiveDeviceLink: { } }
&& (HasComp<DeviceLinkSinkComponent>(args.Target) || HasComp<DeviceLinkSourceComponent>(args.Target)))
{
AlternativeVerb verb = new()
{
Text = Loc.GetString("network-configurator-link-defaults"),
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/in.svg.192dpi.png")),
Act = () => TryLinkDefaults(args.Using.Value, configurator, args.Target, args.User),
Impact = LogImpact.Low
};
args.Verbs.Add(verb);
}
}
private void OnAddSwitchModeVerb(EntityUid uid, NetworkConfiguratorComponent configurator, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue || !HasComp<NetworkConfiguratorComponent>(args.Target))
return;
AlternativeVerb verb = new()
{
Text = Loc.GetString("network-configurator-switch-mode"),
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")),
Act = () => SwitchMode(args.User, args.Target, configurator),
Impact = LogImpact.Low
};
args.Verbs.Add(verb);
}
#endregion
#region UI
private void OpenDeviceLinkUi(EntityUid configuratorUid, EntityUid? targetUid, EntityUid userUid, NetworkConfiguratorComponent configurator)
{
if (Delay(configurator))
return;
if (!targetUid.HasValue || !configurator.ActiveDeviceLink.HasValue || !TryComp(userUid, out ActorComponent? actor) || !AccessCheck(targetUid.Value, userUid, configurator))
return;
_uiSystem.TryOpen(configuratorUid, NetworkConfiguratorUiKey.Link, actor.PlayerSession);
configurator.DeviceLinkTarget = targetUid;
if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(targetUid, out DeviceLinkSinkComponent? targetSink))
{
UpdateLinkUiState(configuratorUid, configurator.ActiveDeviceLink.Value, targetUid.Value, activeSource, targetSink);
}
else if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink)
&& TryComp(targetUid, out DeviceLinkSourceComponent? targetSource))
{
UpdateLinkUiState(configuratorUid, targetUid.Value, configurator.ActiveDeviceLink.Value, targetSource, activeSink);
}
}
private void UpdateLinkUiState(EntityUid configuratorUid, EntityUid sourceUid, EntityUid sinkUid,
DeviceLinkSourceComponent? sourceComponent = null, DeviceLinkSinkComponent? sinkComponent = null,
DeviceNetworkComponent? sourceNetworkComponent = null, DeviceNetworkComponent? sinkNetworkComponent = null)
{
if (!Resolve(sourceUid, ref sourceComponent, false) || !Resolve(sinkUid, ref sinkComponent, false))
return;
var sources = _deviceLinkSystem.GetSourcePorts(sourceUid, sourceComponent);
var sinks = _deviceLinkSystem.GetSinkPorts(sinkUid, sinkComponent);
var links = _deviceLinkSystem.GetLinks(sourceUid, sinkUid, sourceComponent);
var defaults = _deviceLinkSystem.GetDefaults(sources);
var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.Address : "";
var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : "";
var state = new DeviceLinkUserInterfaceState(sources, sinks, links, sourceAddress, sinkAddress, defaults);
_uiSystem.TrySetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state);
}
/// <summary>
/// Opens the config ui. It can be used to modify the devices in the targets device list.
/// </summary>
private void OpenDeviceListUi(EntityUid configuratorUid, EntityUid? targetUid, EntityUid userUid, NetworkConfiguratorComponent configurator)
{
if (configurator.ActiveDeviceLink == targetUid)
return;
if (Delay(configurator))
return;
if (!targetUid.HasValue || !TryComp(userUid, out ActorComponent? actor) || !AccessCheck(targetUid.Value, userUid, configurator))
return;
if (!TryComp(targetUid, out DeviceListComponent? list))
return;
list.Configurators.Add(configuratorUid);
configurator.ActiveDeviceList = targetUid;
Dirty(configuratorUid, configurator);
if (!_uiSystem.TryGetUi(configuratorUid, NetworkConfiguratorUiKey.Configure, out var bui))
return;
if (_uiSystem.OpenUi(bui, actor.PlayerSession))
_uiSystem.SetUiState(bui, new DeviceListUserInterfaceState(
_deviceListSystem.GetDeviceList(configurator.ActiveDeviceList.Value)
.Select(v => (v.Key, MetaData(v.Value).EntityName)).ToHashSet()
));
}
/// <summary>
/// Sends the list of saved devices to the ui
/// </summary>
private void UpdateListUiState(EntityUid uid, NetworkConfiguratorComponent component)
{
HashSet<(string address, string name)> devices = new();
HashSet<string> invalidDevices = new();
foreach (var pair in component.Devices)
{
if (!Exists(pair.Value))
{
invalidDevices.Add(pair.Key);
continue;
}
devices.Add((pair.Key, Name(pair.Value)));
}
//Remove saved entities that don't exist anymore
foreach (var invalidDevice in invalidDevices)
{
component.Devices.Remove(invalidDevice);
}
if (_uiSystem.TryGetUi(uid, NetworkConfiguratorUiKey.List, out var bui))
_uiSystem.SetUiState(bui, new NetworkConfiguratorUserInterfaceState(devices));
}
/// <summary>
/// Clears the active device list when the ui is closed
/// </summary>
private void OnUiClosed(EntityUid uid, NetworkConfiguratorComponent component, BoundUIClosedEvent args)
{
if (!args.UiKey.Equals(NetworkConfiguratorUiKey.Configure)
&& !args.UiKey.Equals(NetworkConfiguratorUiKey.Link)
&& !args.UiKey.Equals(NetworkConfiguratorUiKey.List))
{
return;
}
if (TryComp(component.ActiveDeviceList, out DeviceListComponent? list))
{
list.Configurators.Remove(uid);
}
component.ActiveDeviceList = null;
if (args.UiKey is NetworkConfiguratorUiKey.Link)
{
component.ActiveDeviceLink = null;
component.DeviceLinkTarget = null;
}
}
public void OnDeviceListShutdown(Entity<NetworkConfiguratorComponent?> conf, Entity<DeviceListComponent> list)
{
list.Comp.Configurators.Remove(conf.Owner);
if (Resolve(conf.Owner, ref conf.Comp))
conf.Comp.ActiveDeviceList = null;
}
/// <summary>
/// Removes a device from the saved devices list
/// </summary>
private void OnRemoveDevice(EntityUid uid, NetworkConfiguratorComponent component, NetworkConfiguratorRemoveDeviceMessage args)
{
if (component.Devices.TryGetValue(args.Address, out var removedDevice) && args.Session.AttachedEntity != null)
{
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} removed buffered device {ToPrettyString(removedDevice):subject} from {ToPrettyString(uid):tool}");
}
component.Devices.Remove(args.Address);
if (TryComp(removedDevice, out DeviceNetworkComponent? device))
device.Configurators.Remove(uid);
UpdateListUiState(uid, component);
}
/// <summary>
/// Clears the saved devices
/// </summary>
private void OnClearDevice(EntityUid uid, NetworkConfiguratorComponent component, NetworkConfiguratorClearDevicesMessage args)
{
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared buffered devices from {ToPrettyString(uid):tool}");
ClearDevices(uid, component);
UpdateListUiState(uid, component);
}
private void ClearDevices(EntityUid uid, NetworkConfiguratorComponent component)
{
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in component.Devices.Values)
{
if (query.TryGetComponent(device, out var comp))
comp.Configurators.Remove(uid);
}
component.Devices.Clear();
}
private void OnClearLinks(EntityUid uid, NetworkConfiguratorComponent configurator, NetworkConfiguratorClearLinksMessage args)
{
if (!configurator.ActiveDeviceLink.HasValue || !configurator.DeviceLinkTarget.HasValue)
return;
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared links between {ToPrettyString(configurator.ActiveDeviceLink.Value):subject} and {ToPrettyString(configurator.DeviceLinkTarget.Value):subject2} with {ToPrettyString(uid):tool}");
if (HasComp<DeviceLinkSourceComponent>(configurator.ActiveDeviceLink) && HasComp<DeviceLinkSinkComponent>(configurator.DeviceLinkTarget))
{
_deviceLinkSystem.RemoveSinkFromSource(
configurator.ActiveDeviceLink.Value,
configurator.DeviceLinkTarget.Value
);
UpdateLinkUiState(
uid,
configurator.ActiveDeviceLink.Value,
configurator.DeviceLinkTarget.Value
);
}
else if (HasComp<DeviceLinkSourceComponent>(configurator.DeviceLinkTarget) && HasComp<DeviceLinkSinkComponent>(configurator.ActiveDeviceLink))
{
_deviceLinkSystem.RemoveSinkFromSource(
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value
);
UpdateLinkUiState(
uid,
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value
);
}
}
private void OnToggleLinks(EntityUid uid, NetworkConfiguratorComponent configurator, NetworkConfiguratorToggleLinkMessage args)
{
if (!configurator.ActiveDeviceLink.HasValue || !configurator.DeviceLinkTarget.HasValue)
return;
if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(configurator.DeviceLinkTarget, out DeviceLinkSinkComponent? targetSink))
{
_deviceLinkSystem.ToggleLink(
args.Session.AttachedEntity,
configurator.ActiveDeviceLink.Value,
configurator.DeviceLinkTarget.Value,
args.Source, args.Sink,
activeSource, targetSink);
UpdateLinkUiState(uid, configurator.ActiveDeviceLink.Value, configurator.DeviceLinkTarget.Value, activeSource);
}
else if (TryComp(configurator.DeviceLinkTarget, out DeviceLinkSourceComponent? targetSource) && TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink))
{
_deviceLinkSystem.ToggleLink(
args.Session.AttachedEntity,
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value,
args.Source, args.Sink,
targetSource, activeSink
);
UpdateLinkUiState(
uid,
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value,
targetSource
);
}
}
/// <summary>
/// Saves links set by the device link UI
/// </summary>
private void OnSaveLinks(EntityUid uid, NetworkConfiguratorComponent configurator, NetworkConfiguratorLinksSaveMessage args)
{
if (!configurator.ActiveDeviceLink.HasValue || !configurator.DeviceLinkTarget.HasValue)
return;
if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(configurator.DeviceLinkTarget, out DeviceLinkSinkComponent? targetSink))
{
_deviceLinkSystem.SaveLinks(
args.Session.AttachedEntity,
configurator.ActiveDeviceLink.Value,
configurator.DeviceLinkTarget.Value,
args.Links,
activeSource,
targetSink
);
UpdateLinkUiState(
uid,
configurator.ActiveDeviceLink.Value,
configurator.DeviceLinkTarget.Value,
activeSource
);
}
else if (TryComp(configurator.DeviceLinkTarget, out DeviceLinkSourceComponent? targetSource) && TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink))
{
_deviceLinkSystem.SaveLinks(
args.Session.AttachedEntity,
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value,
args.Links,
targetSource,
activeSink
);
UpdateLinkUiState(
uid,
configurator.DeviceLinkTarget.Value,
configurator.ActiveDeviceLink.Value,
targetSource
);
}
}
/// <summary>
/// Handles all the button presses from the config ui.
/// Modifies, copies or visualizes the targets device list
/// </summary>
private void OnConfigButtonPressed(EntityUid uid, NetworkConfiguratorComponent component, NetworkConfiguratorButtonPressedMessage args)
{
if (!component.ActiveDeviceList.HasValue)
return;
var result = DeviceListUpdateResult.NoComponent;
switch (args.ButtonKey)
{
case NetworkConfiguratorButtonKey.Set:
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} set device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}");
result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet<EntityUid>(component.Devices.Values));
break;
case NetworkConfiguratorButtonKey.Add:
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} added device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}");
result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet<EntityUid>(component.Devices.Values), true);
break;
case NetworkConfiguratorButtonKey.Clear:
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared device links from {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}");
result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet<EntityUid>());
break;
case NetworkConfiguratorButtonKey.Copy:
if (args.Session.AttachedEntity != null)
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} copied devices from {ToPrettyString(component.ActiveDeviceList.Value):subject} to {ToPrettyString(uid):tool}");
ClearDevices(uid, component);
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var (addr, device) in _deviceListSystem.GetDeviceList(component.ActiveDeviceList.Value))
{
if (query.TryGetComponent(device, out var comp))
{
component.Devices[addr] = device;
comp.Configurators.Add(uid);
}
}
UpdateListUiState(uid, component);
return;
case NetworkConfiguratorButtonKey.Show:
break;
}
var resultText = result switch
{
DeviceListUpdateResult.TooManyDevices => Loc.GetString("network-configurator-too-many-devices"),
DeviceListUpdateResult.UpdateOk => Loc.GetString("network-configurator-update-ok"),
_ => "error"
};
_popupSystem.PopupCursor(Loc.GetString(resultText), args.Session, PopupType.Medium);
_uiSystem.TrySetUiState(
uid,
NetworkConfiguratorUiKey.Configure,
new DeviceListUserInterfaceState(
_deviceListSystem.GetDeviceList(component.ActiveDeviceList.Value)
.Select(v => (v.Key, MetaData(v.Value).EntityName)).ToHashSet()));
}
public void OnDeviceShutdown(Entity<NetworkConfiguratorComponent?> conf, Entity<DeviceNetworkComponent> device)
{
device.Comp.Configurators.Remove(conf.Owner);
if (!Resolve(conf.Owner, ref conf.Comp))
return;
foreach (var (addr, dev) in conf.Comp.Devices)
{
if (device.Owner == dev)
conf.Comp.Devices.Remove(addr);
}
UpdateListUiState(conf, conf.Comp);
}
private void OnUiOpenAttempt(EntityUid uid, NetworkConfiguratorComponent configurator, ActivatableUIOpenAttemptEvent args)
{
if (configurator.LinkModeActive)
args.Cancel();
}
#endregion
}