mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-30 08:07:28 +00:00
* Fix the sensor monitoring console forcing a GC every 3 seconds (#38146) * Optimize sensor monitoring window graph drawing * Add shared static Vector2 pool for all GraphView instances * Address requested changes * remove lock * Update submodule to 264.0.0 (#38629) * Toy/Plushie Inhands and Wearables (#38514) * Fixed dependency injection and some other issues in a few places. * More issue fixes * patchfor broken NetworkConfiguratorLinkMenu (#38632) fix * Fix solutions flickering when transferring contents (#34838) * Use Solution clones when applying SolutionComponent states * Revert "Use Solution clones when applying SolutionComponent states" This reverts commit 013fd111cf92b22562e00f98a7aaa49bc4b4ed62. * Make Solution implement ICloneable and rename Clone method. * Copy CanReact value when cloning a Solution * Convert to IRobustCloneable * Fix typos in guidebook: Buisness → Business (#38636) * Fix typo in `MinorAntagonists.xml` Buisness → Business * Fix typo in `YourFirstCharacter.xml` Buisness → Business * Various Headphones Fixes and Tweaks (#38479) * sprites, wearables * neck * icon-on sprite * Cleanup prototype instantiation in `DamageTest` (#38639) Cleanup prototype instantiation in DamageTest * Cleanup prototype instantiation in `ExplosionSystem` (#38642) Cleanup prototype instantiation in ExplosionSystem * AddBodyPartCommand localization. (#38612) commit * fix ItemSlotsSystem debug assert (#38655) * Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536) * Added directional beacons (#38284) * Added directional beacons Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Fixed names Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Power stat and nuke codes commands get some LEC love. (#38585) * commit * requested changes. * Dsay Dirty and Follow commands converted to LEC and localized. (#38666) * commit * whoopwhoopwhoop * Retro laser sprite fix (#38676) * Fixed everything except the icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fixed icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fix water coolers (#38681) * Monochromacy typo fix (#38686) * fixes the typo * Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504 * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Validate `CloningSettingsPrototype`s (#38688) * Validate CloningSettingsPrototypes * Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Check EventComponents too --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Add test of objective-related console commands (#36400) * Add test of objective add/list/remove commands * Not sure why we're validating test prototypes, but sure * We don't need a map * Improvements and fixups for New Status Effect API (#38660) * Predict healing and bloodstream (#38690) * initial commit * reapply 38126 * fix rootable * someone missed an important minus sign here * try this * fix * fix * reenable crit hits * cleanup * fix status time dirtying * fix * camelCase * Healing and bloodstream prediction fixes. * Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661) * Resolving Wizard Recall on Nuke disk making it impossible to disarm - Adding a DisarmBomb case to nuke status update loop - Changing a few methods and parameters to properly follow formatting standards - Updating some names to follow camelCase * Updating missed tag * Reverting DataField change Should prevent this preventative bugfix being a breaking change. * Switch HSV to the default colorspace for character customization (#38434) * Made HSV default for character editor * Adds/fixes comments to HSV defaulting * Added dropbox fix, potentially cursed * Revert "Added dropbox fix, potentially cursed" This reverts commit a709883366fbee813e839742125e70844672af29. --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Fix: Don't deploy foldables when clicking on items inside containers (#38709) * Fix * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Pressure Relief Valve (#36708) * initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Fix TextLinkTag (#32203) * Adjust uplink buy button to be under item icon (#38596) * Adjusted uplink buy button to be under item icon * Put the discount subtext under the icon * Indent fixes, added margin --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Scurrets - Audio Improvements (#38482) * Scurret audio tuning * Add new sfx * Update sneezing sfx * YAML support * Rename a folder * make telesci wreck easier (#37569) rel * Validate `ShaderPrototype` IDs (#38728) * Convert all shader prototype string literals to protoids in overlays * Convert more shader prototype literal strings to protoids * Convert ValidatePrototypeId to ProtoId * Later * [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664) * fixed * clean up * orks fix smart * review fix 1 * more requested changes * less cursed * more descriptive description * better wording * Tiny Tiny Cleanup of the EyeClosingSystem. (#38734) Update EyeClosingSystem.cs * Fix human skin tone distribution (#38701) * fix: Use PredictedQueueDel for gib spell (#38729) * fix: don't default to uncharged sprite state for cells (#38730) * Fix Hristov description - remove inaccurate technical specs (#38746) - Removes inaccurate 'armor piercing 14.5mm shells' reference - Replaces it with a more funny description, matching the style of the other snipers and guns - Keeps ammunition type '.60 anti-materiel ammo' specification - Fixes issue #38590 Co-authored-by: Arthur Fiorese de Andrade <aandrade@cmcxs.gov.br> * feat: allow mopping evaporating puddles (#38743) * Validate remaining `ProtoId` strings (#38747) Validate remaining ProtoId strings * Validate `ProtoId`s in tests (#38745) * Convert string literals to protoids in Content.Tests * Convert string literals to protoids or consts in Content.IntegrationTests * Fix linter failures Tricksy static using misled me * Cleanup warning in StomachSystem (#38748) you did not see this * Vox scars (#38592) * Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl * Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl" This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15. * locale key fix * Changed top surgery scar names to be more generalized * Adjusted face scars * Formatting fixes --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * UnlockNode command to LEC. (#38751) * commit * Update UnlockNodeCommand.cs * commit * move command locale to its own file. * Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Typofixes for figurine dialogue (#38737) * Typofixes for figurine dialogue * Forgot two * Janitor Tool: Wire Brush (#38667) * Wow! It's -brush- * spacing. * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * fixed changes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Minor escape menu UX improvements (#38650) * fix: spellbooks can have infinite charges (#38376) * fix: spellbooks can have infinite charges * refactor: indicate infinite spellbook charges with null Not sure if I like this much better...
853 lines
36 KiB
C#
853 lines
36 KiB
C#
using System.Linq;
|
|
using Content.Server.Administration.Logs;
|
|
using Content.Server.DeviceLinking.Systems;
|
|
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.UserInterface;
|
|
using Content.Shared.Verbs;
|
|
using JetBrains.Annotations;
|
|
using Robust.Server.Audio;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Map.Events;
|
|
using Robust.Shared.Prototypes;
|
|
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, BoundUserInterfaceCheckRangeEvent>(OnUiRangeCheck);
|
|
|
|
SubscribeLocalEvent<DeviceListComponent, ComponentRemove>(OnComponentRemoved);
|
|
|
|
SubscribeLocalEvent<BeforeSerializationEvent>(OnMapSave);
|
|
}
|
|
|
|
private void OnMapSave(BeforeSerializationEvent ev)
|
|
{
|
|
var enumerator = AllEntityQuery<NetworkConfiguratorComponent>();
|
|
while (enumerator.MoveNext(out var uid, out var conf))
|
|
{
|
|
if (!TryComp(conf.ActiveDeviceList, out TransformComponent? listXform))
|
|
continue;
|
|
|
|
if (!ev.MapIds.Contains(listXform.MapID))
|
|
continue;
|
|
|
|
// The linked device list is (probably) being saved. Make sure that the configurator is also being saved
|
|
// (i.e., not in the hands of a mapper/ghost). In the future, map saving should raise a separate event
|
|
// containing a set of all entities that are about to be saved, which would make checking this much easier.
|
|
// This is a shitty bandaid, and will force close the UI during auto-saves.
|
|
// TODO Map serialization refactor
|
|
// I'm refactoring it now and I still dont know what to do
|
|
|
|
var xform = Transform(uid);
|
|
if (ev.MapIds.Contains(xform.MapID) && IsSaveable(uid))
|
|
continue;
|
|
|
|
_uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure);
|
|
DebugTools.AssertNull(conf.ActiveDeviceList);
|
|
}
|
|
|
|
bool IsSaveable(EntityUid uid)
|
|
{
|
|
while (uid.IsValid())
|
|
{
|
|
if (Prototype(uid)?.MapSavable == false)
|
|
return false;
|
|
uid = Transform(uid).ParentUid;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void OnUiRangeCheck(Entity<NetworkConfiguratorComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
|
|
{
|
|
if (ent.Comp.ActiveDeviceList == null || args.Result == BoundUserInterfaceRangeResult.Fail)
|
|
return;
|
|
|
|
DebugTools.Assert(Exists(ent.Comp.ActiveDeviceList));
|
|
if (!_interactionSystem.InRangeUnobstructed(args.Actor!, ent.Comp.ActiveDeviceList.Value))
|
|
args.Result = BoundUserInterfaceRangeResult.Fail;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
//This checks if the device is marked as having a savable address,
|
|
//to avoid adding pdas and whatnot to air alarms. This flag is true
|
|
//by default, so this will only prevent devices from being added to
|
|
//network configurator lists if manually set to false in the prototype
|
|
if (!device.SavableAddress)
|
|
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.CloseUi(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(configuratorUid, 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 || !AccessCheck(targetUid.Value, userUid, configurator))
|
|
return;
|
|
|
|
|
|
_uiSystem.OpenUi(configuratorUid, NetworkConfiguratorUiKey.Link, userUid);
|
|
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.GetSinkPortIds((sinkUid, sinkComponent));
|
|
var links = _deviceLinkSystem.GetLinks(sourceUid, sinkUid, sourceComponent);
|
|
var defaults = _deviceLinkSystem.GetDefaults(sources);
|
|
var sourceIds = sources.Select(s => (ProtoId<SourcePortPrototype>)s.ID).ToArray();
|
|
|
|
var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.Address : "";
|
|
var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : "";
|
|
|
|
var state = new DeviceLinkUserInterfaceState(sourceIds, sinks, links, sourceAddress, sinkAddress, defaults);
|
|
_uiSystem.SetUiState(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 || !AccessCheck(targetUid.Value, userUid, configurator))
|
|
return;
|
|
|
|
if (!TryComp(targetUid, out DeviceListComponent? list))
|
|
return;
|
|
|
|
if (TryComp(configurator.ActiveDeviceList, out DeviceListComponent? oldList))
|
|
oldList.Configurators.Remove(configuratorUid);
|
|
|
|
list.Configurators.Add(configuratorUid);
|
|
configurator.ActiveDeviceList = targetUid;
|
|
Dirty(configuratorUid, configurator);
|
|
|
|
if (_uiSystem.TryOpenUi(configuratorUid, NetworkConfiguratorUiKey.Configure, userUid))
|
|
{
|
|
_uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Configure, 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);
|
|
}
|
|
|
|
_uiSystem.SetUiState(uid, NetworkConfiguratorUiKey.List, 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))
|
|
{
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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)
|
|
{
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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;
|
|
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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.Actor,
|
|
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.Actor,
|
|
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.Actor,
|
|
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.Actor,
|
|
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:
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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:
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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:
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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:
|
|
_adminLogger.Add(LogType.DeviceLinking, LogImpact.Low,
|
|
$"{ToPrettyString(args.Actor):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.Add(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.Actor, PopupType.Medium);
|
|
_uiSystem.SetUiState(
|
|
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
|
|
}
|