2022-12-19 10:41:47 +13:00
using System.Linq ;
2023-06-27 20:03:39 -05:00
using Content.Server.Administration.Logs ;
2023-05-07 08:07:24 +02:00
using Content.Server.DeviceLinking.Systems ;
2022-09-05 17:55:44 -07:00
using Content.Server.DeviceNetwork.Components ;
2022-06-10 03:28:24 +02:00
using Content.Shared.Access.Components ;
using Content.Shared.Access.Systems ;
using Content.Shared.Database ;
2023-05-07 08:07:24 +02:00
using Content.Shared.DeviceLinking ;
2022-06-10 03:28:24 +02:00
using Content.Shared.DeviceNetwork ;
2023-05-07 08:07:24 +02:00
using Content.Shared.DeviceNetwork.Components ;
using Content.Shared.DeviceNetwork.Systems ;
using Content.Shared.Examine ;
2022-06-10 03:28:24 +02:00
using Content.Shared.Interaction ;
using Content.Shared.Popups ;
2024-02-01 11:45:24 +03:00
using Content.Shared.UserInterface ;
2022-06-10 03:28:24 +02:00
using Content.Shared.Verbs ;
using JetBrains.Annotations ;
2023-11-27 22:12:34 +11:00
using Robust.Server.Audio ;
2022-06-10 03:28:24 +02:00
using Robust.Server.GameObjects ;
using Robust.Shared.Audio ;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player ;
2023-05-07 08:07:24 +02:00
using Robust.Shared.Timing ;
2023-02-26 18:48:57 +11:00
using Robust.Shared.Utility ;
2022-06-10 03:28:24 +02:00
namespace Content.Server.DeviceNetwork.Systems ;
[UsedImplicitly]
2022-09-05 17:55:44 -07:00
public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
2022-06-10 03:28:24 +02:00
{
[Dependency] private readonly DeviceListSystem _deviceListSystem = default ! ;
2023-05-07 08:07:24 +02:00
[Dependency] private readonly DeviceLinkSystem _deviceLinkSystem = default ! ;
2022-06-10 03:28:24 +02:00
[Dependency] private readonly SharedPopupSystem _popupSystem = default ! ;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default ! ;
[Dependency] private readonly AccessReaderSystem _accessSystem = default ! ;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default ! ;
2023-05-07 08:07:24 +02:00
[Dependency] private readonly AudioSystem _audioSystem = default ! ;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default ! ;
[Dependency] private readonly IGameTiming _gameTiming = default ! ;
2023-06-27 20:03:39 -05:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2022-06-10 03:28:24 +02:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-08-30 21:56:42 -07:00
SubscribeLocalEvent < NetworkConfiguratorComponent , MapInitEvent > ( OnMapInit ) ;
2023-12-21 23:18:40 -05:00
SubscribeLocalEvent < NetworkConfiguratorComponent , ComponentShutdown > ( OnShutdown ) ;
2022-08-30 21:56:42 -07:00
2022-06-10 03:28:24 +02:00
//Interaction
2023-05-07 08:07:24 +02:00
SubscribeLocalEvent < NetworkConfiguratorComponent , AfterInteractEvent > ( AfterInteract ) ; //TODO: Replace with utility verb?
SubscribeLocalEvent < NetworkConfiguratorComponent , ExaminedEvent > ( DoExamine ) ;
2022-06-10 03:28:24 +02:00
//Verbs
SubscribeLocalEvent < NetworkConfiguratorComponent , GetVerbsEvent < UtilityVerb > > ( OnAddInteractVerb ) ;
SubscribeLocalEvent < DeviceNetworkComponent , GetVerbsEvent < AlternativeVerb > > ( OnAddAlternativeSaveDeviceVerb ) ;
2023-05-07 08:07:24 +02:00
SubscribeLocalEvent < NetworkConfiguratorComponent , GetVerbsEvent < AlternativeVerb > > ( OnAddSwitchModeVerb ) ;
2022-06-10 03:28:24 +02:00
//UI
SubscribeLocalEvent < NetworkConfiguratorComponent , BoundUIClosedEvent > ( OnUiClosed ) ;
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorRemoveDeviceMessage > ( OnRemoveDevice ) ;
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorClearDevicesMessage > ( OnClearDevice ) ;
2023-05-07 08:07:24 +02:00
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorLinksSaveMessage > ( OnSaveLinks ) ;
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorClearLinksMessage > ( OnClearLinks ) ;
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorToggleLinkMessage > ( OnToggleLinks ) ;
2022-06-10 03:28:24 +02:00
SubscribeLocalEvent < NetworkConfiguratorComponent , NetworkConfiguratorButtonPressedMessage > ( OnConfigButtonPressed ) ;
2023-05-07 08:07:24 +02:00
SubscribeLocalEvent < NetworkConfiguratorComponent , ActivatableUIOpenAttemptEvent > ( OnUiOpenAttempt ) ;
2022-06-10 03:28:24 +02:00
SubscribeLocalEvent < DeviceListComponent , ComponentRemove > ( OnComponentRemoved ) ;
}
2023-12-21 23:18:40 -05:00
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 ;
}
2022-06-10 03:28:24 +02:00
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
2023-07-08 09:02:17 -07:00
var query = EntityQueryEnumerator < NetworkConfiguratorComponent > ( ) ;
while ( query . MoveNext ( out var uid , out var component ) )
2022-06-10 03:28:24 +02:00
{
2023-07-08 09:02:17 -07:00
if ( component . ActiveDeviceList ! = null
& & EntityManager . EntityExists ( component . ActiveDeviceList . Value )
& & _interactionSystem . InRangeUnobstructed ( uid , component . ActiveDeviceList . Value ) )
2023-02-26 18:48:57 +11:00
continue ;
2022-06-10 03:28:24 +02:00
//The network configurator is a handheld device. There can only ever be an ui session open for the player holding the device.
2023-05-07 08:07:24 +02:00
_uiSystem . TryCloseAll ( uid , NetworkConfiguratorUiKey . Configure ) ;
2022-06-10 03:28:24 +02:00
}
}
2022-08-30 21:56:42 -07:00
private void OnMapInit ( EntityUid uid , NetworkConfiguratorComponent component , MapInitEvent args )
{
2023-05-07 08:07:24 +02:00
UpdateListUiState ( uid , component ) ;
2022-08-30 21:56:42 -07:00
}
2022-06-10 03:28:24 +02:00
private void TryAddNetworkDevice ( EntityUid ? targetUid , EntityUid configuratorUid , EntityUid userUid ,
NetworkConfiguratorComponent ? configurator = null )
{
if ( ! Resolve ( configuratorUid , ref configurator ) )
return ;
2023-07-08 09:02:17 -07:00
TryAddNetworkDevice ( configuratorUid , targetUid , userUid , configurator ) ;
2022-06-10 03:28:24 +02:00
}
2023-07-08 09:02:17 -07:00
private void TryAddNetworkDevice ( EntityUid configuratorUid , EntityUid ? targetUid , EntityUid userUid , NetworkConfiguratorComponent configurator , DeviceNetworkComponent ? device = null )
2022-06-10 03:28:24 +02:00
{
2022-06-28 22:54:08 +10:00
if ( ! targetUid . HasValue | | ! Resolve ( targetUid . Value , ref device , false ) )
2022-06-10 03:28:24 +02:00
return ;
2022-08-30 21:56:42 -07:00
var address = device . Address ;
if ( string . IsNullOrEmpty ( address ) )
2022-06-10 03:28:24 +02:00
{
2022-09-01 21:36:54 -07:00
// 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.
2022-08-30 21:56:42 -07:00
if ( MetaData ( targetUid . Value ) . EntityLifeStage = = EntityLifeStage . MapInitialized )
{
_popupSystem . PopupCursor ( Loc . GetString ( "network-configurator-device-failed" , ( "device" , targetUid ) ) ,
2022-12-19 10:41:47 +13:00
userUid ) ;
2022-08-30 21:56:42 -07:00
return ;
}
2023-07-08 09:02:17 -07:00
address = $"UID: {targetUid.Value}" ;
2022-06-10 03:28:24 +02:00
}
if ( configurator . Devices . ContainsValue ( targetUid . Value ) )
{
2022-12-19 10:41:47 +13:00
_popupSystem . PopupCursor ( Loc . GetString ( "network-configurator-device-already-saved" , ( "device" , targetUid ) ) , userUid ) ;
2022-06-10 03:28:24 +02:00
return ;
}
2023-12-21 23:18:40 -05:00
device . Configurators . Add ( configuratorUid ) ;
2022-08-30 21:56:42 -07:00
configurator . Devices . Add ( address , targetUid . Value ) ;
2022-06-10 03:28:24 +02:00
_popupSystem . PopupCursor ( Loc . GetString ( "network-configurator-device-saved" , ( "address" , device . Address ) , ( "device" , targetUid ) ) ,
2022-12-19 10:41:47 +13:00
userUid , PopupType . Medium ) ;
2022-06-10 03:28:24 +02:00
2023-06-27 20:03:39 -05:00
_adminLogger . Add ( LogType . DeviceLinking , LogImpact . Low , $"{ToPrettyString(userUid):actor} saved {ToPrettyString(targetUid.Value):subject} to {ToPrettyString(configuratorUid):tool}" ) ;
UpdateListUiState ( configuratorUid , configurator ) ;
2023-05-07 08:07:24 +02:00
}
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 ;
}
2023-05-10 03:50:34 +05:00
if ( configurator . ActiveDeviceLink . HasValue
& & ( HasComp < DeviceLinkSourceComponent > ( target )
& & HasComp < DeviceLinkSinkComponent > ( configurator . ActiveDeviceLink )
| | HasComp < DeviceLinkSinkComponent > ( target )
& & HasComp < DeviceLinkSourceComponent > ( configurator . ActiveDeviceLink ) ) )
2023-05-07 08:07:24 +02:00
{
2023-05-10 03:50:34 +05:00
OpenDeviceLinkUi ( uid , target , user , configurator ) ;
2023-05-07 08:07:24 +02:00
return ;
}
2023-05-10 03:50:34 +05:00
if ( HasComp < DeviceLinkSourceComponent > ( target ) & & HasComp < DeviceLinkSourceComponent > ( configurator . ActiveDeviceLink )
| | HasComp < DeviceLinkSinkComponent > ( target ) & & HasComp < DeviceLinkSinkComponent > ( configurator . ActiveDeviceLink ) )
2023-05-07 08:07:24 +02:00
return ;
2023-07-08 09:02:17 -07:00
_popupSystem . PopupEntity ( Loc . GetString ( "network-configurator-link-mode-started" , ( "device" , Name ( target . Value ) ) ) , target . Value , user ) ;
2023-05-07 08:07:24 +02:00
configurator . ActiveDeviceLink = target ;
}
2023-07-08 09:02:17 -07:00
private void TryLinkDefaults ( EntityUid _ , NetworkConfiguratorComponent configurator , EntityUid ? targetUid , EntityUid user )
2023-05-07 08:07:24 +02:00
{
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 ) ;
}
2022-06-10 03:28:24 +02:00
}
private bool AccessCheck ( EntityUid target , EntityUid ? user , NetworkConfiguratorComponent component )
{
if ( ! TryComp ( target , out AccessReaderComponent ? reader ) | | user = = null )
2023-05-07 08:07:24 +02:00
return true ;
2022-06-10 03:28:24 +02:00
2023-09-03 13:05:22 +12:00
if ( _accessSystem . IsAllowed ( user . Value , target , reader ) )
2022-06-10 03:28:24 +02:00
return true ;
2023-05-07 08:07:24 +02:00
_audioSystem . PlayPvs ( component . SoundNoAccess , user . Value , AudioParams . Default . WithVolume ( - 2f ) . WithPitchScale ( 1.2f ) ) ;
2022-12-19 10:41:47 +13:00
_popupSystem . PopupEntity ( Loc . GetString ( "network-configurator-device-access-denied" ) , target , user . Value ) ;
2022-06-10 03:28:24 +02:00
return false ;
}
private void OnComponentRemoved ( EntityUid uid , DeviceListComponent component , ComponentRemove args )
{
2023-05-07 08:07:24 +02:00
_uiSystem . TryCloseAll ( uid , NetworkConfiguratorUiKey . Configure ) ;
}
2023-05-22 15:20:53 +02:00
/// <summary>
/// Toggles between linking and listing mode
/// </summary>
2023-05-07 08:07:24 +02:00
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 ;
2023-05-22 15:20:53 +02:00
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 ) ;
}
2023-05-07 08:07:24 +02:00
2023-05-22 15:20:53 +02:00
/// <summary>
/// Updates the configurators appearance and plays a sound indicating that the mode switched
/// </summary>
private void UpdateModeAppearance ( EntityUid userUid , EntityUid configuratorUid , NetworkConfiguratorComponent configurator )
{
2023-05-07 08:07:24 +02:00
Dirty ( configurator ) ;
_appearanceSystem . SetData ( configuratorUid , NetworkConfiguratorVisuals . Mode , configurator . LinkModeActive ) ;
var pitch = configurator . LinkModeActive ? 1 : 0.8f ;
2023-05-22 15:20:53 +02:00
_audioSystem . PlayPvs ( configurator . SoundSwitchMode , userUid , AudioParams . Default . WithVolume ( 1.5f ) . WithPitchScale ( pitch ) ) ;
2023-05-07 08:07:24 +02:00
}
/// <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 ;
2022-06-10 03:28:24 +02:00
}
#region Interactions
2023-05-07 08:07:24 +02:00
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 ) ;
}
2022-06-10 03:28:24 +02:00
/// <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>
2023-05-07 08:07:24 +02:00
private void OnUsed ( EntityUid uid , NetworkConfiguratorComponent configurator , EntityUid ? target , EntityUid user , bool canReach = true )
2022-06-10 03:28:24 +02:00
{
2023-05-07 08:07:24 +02:00
if ( ! canReach | | ! target . HasValue )
2022-06-10 03:28:24 +02:00
return ;
2023-05-22 15:20:53 +02:00
DetermineMode ( uid , configurator , target , user ) ;
2023-05-07 08:07:24 +02:00
if ( configurator . LinkModeActive )
{
TryLinkDevice ( uid , configurator , target , user ) ;
return ;
}
2022-06-10 03:28:24 +02:00
if ( ! HasComp < DeviceListComponent > ( target ) )
{
2023-07-08 09:02:17 -07:00
TryAddNetworkDevice ( uid , target , user , configurator ) ;
2022-06-10 03:28:24 +02:00
return ;
}
2023-07-08 09:02:17 -07:00
OpenDeviceListUi ( uid , target , user , configurator ) ;
2022-06-10 03:28:24 +02:00
}
2023-05-22 15:20:53 +02:00
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 ) ;
}
2022-06-10 03:28:24 +02:00
#endregion
#region Verbs
/// <summary>
/// Adds the interaction verb which is either configuring device lists or saving a device onto the configurator
/// </summary>
2023-05-07 08:07:24 +02:00
private void OnAddInteractVerb ( EntityUid uid , NetworkConfiguratorComponent configurator , GetVerbsEvent < UtilityVerb > args )
2022-06-10 03:28:24 +02:00
{
2023-05-07 08:07:24 +02:00
if ( ! args . CanAccess | | ! args . CanInteract | | ! args . Using . HasValue )
2022-06-10 03:28:24 +02:00
return ;
2023-05-07 08:07:24 +02:00
var verb = new UtilityVerb
2022-06-10 03:28:24 +02:00
{
2023-05-07 08:07:24 +02:00
Act = ( ) = > OnUsed ( uid , configurator , args . Target , args . User ) ,
2022-06-10 03:28:24 +02:00
Impact = LogImpact . Low
} ;
2023-05-07 08:07:24 +02:00
2023-05-07 12:58:12 +02:00
if ( configurator . LinkModeActive & & ( HasComp < DeviceLinkSinkComponent > ( args . Target ) | | HasComp < DeviceLinkSourceComponent > ( args . Target ) ) )
2023-05-07 08:07:24 +02:00
{
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" ) ) ;
2023-05-07 12:58:12 +02:00
args . Verbs . Add ( verb ) ;
2023-05-07 08:07:24 +02:00
}
2023-05-07 12:58:12 +02:00
else if ( HasComp < DeviceNetworkComponent > ( args . Target ) )
2023-05-07 08:07:24 +02:00
{
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" ) ) ;
2023-05-07 12:58:12 +02:00
args . Verbs . Add ( verb ) ;
2023-05-07 08:07:24 +02:00
}
2022-06-10 03:28:24 +02:00
}
/// <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 )
{
2023-05-07 08:07:24 +02:00
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 ;
}
2023-07-08 09:02:17 -07:00
if ( configurator is { LinkModeActive : true , ActiveDeviceLink : { } }
& & ( HasComp < DeviceLinkSinkComponent > ( args . Target ) | | HasComp < DeviceLinkSourceComponent > ( args . Target ) ) )
2023-05-07 08:07:24 +02:00
{
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 ) )
2022-06-10 03:28:24 +02:00
return ;
AlternativeVerb verb = new ( )
{
2023-05-07 12:58:12 +02:00
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 ) ,
2022-06-10 03:28:24 +02:00
Impact = LogImpact . Low
} ;
args . Verbs . Add ( verb ) ;
}
#endregion
#region UI
2023-05-07 08:07:24 +02:00
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 )
{
2023-05-29 08:07:59 +02:00
if ( ! Resolve ( sourceUid , ref sourceComponent , false ) | | ! Resolve ( sinkUid , ref sinkComponent , false ) )
2023-05-07 08:07:24 +02:00
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 ) ;
2023-05-29 08:07:59 +02:00
var sourceAddress = Resolve ( sourceUid , ref sourceNetworkComponent , false ) ? sourceNetworkComponent . Address : "" ;
var sinkAddress = Resolve ( sinkUid , ref sinkNetworkComponent , false ) ? sinkNetworkComponent . Address : "" ;
2023-05-07 08:07:24 +02:00
var state = new DeviceLinkUserInterfaceState ( sources , sinks , links , sourceAddress , sinkAddress , defaults ) ;
_uiSystem . TrySetUiState ( configuratorUid , NetworkConfiguratorUiKey . Link , state ) ;
}
2022-06-10 03:28:24 +02:00
/// <summary>
/// Opens the config ui. It can be used to modify the devices in the targets device list.
/// </summary>
2023-07-08 09:02:17 -07:00
private void OpenDeviceListUi ( EntityUid configuratorUid , EntityUid ? targetUid , EntityUid userUid , NetworkConfiguratorComponent configurator )
2022-06-10 03:28:24 +02:00
{
2023-12-21 23:18:40 -05:00
if ( configurator . ActiveDeviceLink = = targetUid )
return ;
2023-05-07 08:07:24 +02:00
if ( Delay ( configurator ) )
return ;
2022-06-10 03:28:24 +02:00
if ( ! targetUid . HasValue | | ! TryComp ( userUid , out ActorComponent ? actor ) | | ! AccessCheck ( targetUid . Value , userUid , configurator ) )
return ;
2023-12-21 23:18:40 -05:00
if ( ! TryComp ( targetUid , out DeviceListComponent ? list ) )
return ;
list . Configurators . Add ( configuratorUid ) ;
2022-06-10 03:28:24 +02:00
configurator . ActiveDeviceList = targetUid ;
2023-12-21 23:18:40 -05:00
Dirty ( configuratorUid , configurator ) ;
2023-07-08 09:02:17 -07:00
if ( ! _uiSystem . TryGetUi ( configuratorUid , NetworkConfiguratorUiKey . Configure , out var bui ) )
return ;
if ( _uiSystem . OpenUi ( bui , actor . PlayerSession ) )
2023-09-11 09:42:41 +10:00
_uiSystem . SetUiState ( bui , new DeviceListUserInterfaceState (
2022-09-05 18:22:39 -07:00
_deviceListSystem . GetDeviceList ( configurator . ActiveDeviceList . Value )
2023-07-08 09:02:17 -07:00
. Select ( v = > ( v . Key , MetaData ( v . Value ) . EntityName ) ) . ToHashSet ( )
) ) ;
2022-06-10 03:28:24 +02:00
}
/// <summary>
/// Sends the list of saved devices to the ui
/// </summary>
2023-05-07 08:07:24 +02:00
private void UpdateListUiState ( EntityUid uid , NetworkConfiguratorComponent component )
2022-06-10 03:28:24 +02:00
{
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 ) ;
}
2023-07-08 09:02:17 -07:00
if ( _uiSystem . TryGetUi ( uid , NetworkConfiguratorUiKey . List , out var bui ) )
2023-09-11 09:42:41 +10:00
_uiSystem . SetUiState ( bui , new NetworkConfiguratorUserInterfaceState ( devices ) ) ;
2022-06-10 03:28:24 +02:00
}
/// <summary>
/// Clears the active device list when the ui is closed
/// </summary>
private void OnUiClosed ( EntityUid uid , NetworkConfiguratorComponent component , BoundUIClosedEvent args )
{
2024-01-14 08:18:39 +01:00
if ( ! args . UiKey . Equals ( NetworkConfiguratorUiKey . Configure )
& & ! args . UiKey . Equals ( NetworkConfiguratorUiKey . Link )
& & ! args . UiKey . Equals ( NetworkConfiguratorUiKey . List ) )
{
return ;
}
2023-12-21 23:18:40 -05:00
if ( TryComp ( component . ActiveDeviceList , out DeviceListComponent ? list ) )
{
list . Configurators . Remove ( uid ) ;
}
2023-05-07 08:07:24 +02:00
2023-12-26 23:39:04 -05:00
component . ActiveDeviceList = null ;
2023-05-07 08:07:24 +02:00
if ( args . UiKey is NetworkConfiguratorUiKey . Link )
{
component . ActiveDeviceLink = null ;
component . DeviceLinkTarget = null ;
}
2022-06-10 03:28:24 +02:00
}
2023-12-21 23:18:40 -05:00
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 ;
}
2022-06-10 03:28:24 +02:00
/// <summary>
/// Removes a device from the saved devices list
/// </summary>
private void OnRemoveDevice ( EntityUid uid , NetworkConfiguratorComponent component , NetworkConfiguratorRemoveDeviceMessage args )
{
2023-06-27 20:03:39 -05:00
if ( component . Devices . TryGetValue ( args . Address , out var removedDevice ) & & args . Session . AttachedEntity ! = null )
2023-12-21 23:18:40 -05:00
{
2023-06-27 20:03:39 -05:00
_adminLogger . Add ( LogType . DeviceLinking , LogImpact . Low ,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} removed buffered device {ToPrettyString(removedDevice):subject} from {ToPrettyString(uid):tool}" ) ;
2023-12-21 23:18:40 -05:00
}
2022-06-10 03:28:24 +02:00
component . Devices . Remove ( args . Address ) ;
2023-12-21 23:18:40 -05:00
if ( TryComp ( removedDevice , out DeviceNetworkComponent ? device ) )
device . Configurators . Remove ( uid ) ;
2023-05-07 08:07:24 +02:00
UpdateListUiState ( uid , component ) ;
2022-06-10 03:28:24 +02:00
}
/// <summary>
/// Clears the saved devices
/// </summary>
2023-06-27 20:03:39 -05:00
private void OnClearDevice ( EntityUid uid , NetworkConfiguratorComponent component , NetworkConfiguratorClearDevicesMessage args )
2022-06-10 03:28:24 +02:00
{
2023-06-27 20:03:39 -05:00
if ( args . Session . AttachedEntity ! = null )
_adminLogger . Add ( LogType . DeviceLinking , LogImpact . Low ,
$"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared buffered devices from {ToPrettyString(uid):tool}" ) ;
2023-12-21 23:18:40 -05:00
ClearDevices ( uid , component ) ;
2023-05-07 08:07:24 +02:00
UpdateListUiState ( uid , component ) ;
}
2023-12-21 23:18:40 -05:00
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 ( ) ;
}
2023-05-07 08:07:24 +02:00
private void OnClearLinks ( EntityUid uid , NetworkConfiguratorComponent configurator , NetworkConfiguratorClearLinksMessage args )
{
if ( ! configurator . ActiveDeviceLink . HasValue | | ! configurator . DeviceLinkTarget . HasValue )
return ;
2023-06-27 20:03:39 -05:00
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}" ) ;
2023-05-12 00:16:02 +02:00
if ( HasComp < DeviceLinkSourceComponent > ( configurator . ActiveDeviceLink ) & & HasComp < DeviceLinkSinkComponent > ( configurator . DeviceLinkTarget ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_deviceLinkSystem . RemoveSinkFromSource (
configurator . ActiveDeviceLink . Value ,
configurator . DeviceLinkTarget . Value
) ;
UpdateLinkUiState (
uid ,
configurator . ActiveDeviceLink . Value ,
configurator . DeviceLinkTarget . Value
) ;
2023-05-07 08:07:24 +02:00
}
2023-05-12 00:16:02 +02:00
else if ( HasComp < DeviceLinkSourceComponent > ( configurator . DeviceLinkTarget ) & & HasComp < DeviceLinkSinkComponent > ( configurator . ActiveDeviceLink ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_deviceLinkSystem . RemoveSinkFromSource (
configurator . DeviceLinkTarget . Value ,
configurator . ActiveDeviceLink . Value
) ;
UpdateLinkUiState (
uid ,
configurator . DeviceLinkTarget . Value ,
configurator . ActiveDeviceLink . Value
) ;
2023-05-07 08:07:24 +02:00
}
}
private void OnToggleLinks ( EntityUid uid , NetworkConfiguratorComponent configurator , NetworkConfiguratorToggleLinkMessage args )
{
if ( ! configurator . ActiveDeviceLink . HasValue | | ! configurator . DeviceLinkTarget . HasValue )
return ;
2023-05-12 00:16:02 +02:00
if ( TryComp ( configurator . ActiveDeviceLink , out DeviceLinkSourceComponent ? activeSource ) & & TryComp ( configurator . DeviceLinkTarget , out DeviceLinkSinkComponent ? targetSink ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_deviceLinkSystem . ToggleLink (
args . Session . AttachedEntity ,
configurator . ActiveDeviceLink . Value ,
configurator . DeviceLinkTarget . Value ,
args . Source , args . Sink ,
activeSource , targetSink ) ;
2023-05-07 08:07:24 +02:00
UpdateLinkUiState ( uid , configurator . ActiveDeviceLink . Value , configurator . DeviceLinkTarget . Value , activeSource ) ;
}
2023-05-12 00:16:02 +02:00
else if ( TryComp ( configurator . DeviceLinkTarget , out DeviceLinkSourceComponent ? targetSource ) & & TryComp ( configurator . ActiveDeviceLink , out DeviceLinkSinkComponent ? activeSink ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_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
) ;
2023-05-07 08:07:24 +02:00
}
}
/// <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 ;
2023-05-12 00:16:02 +02:00
if ( TryComp ( configurator . ActiveDeviceLink , out DeviceLinkSourceComponent ? activeSource ) & & TryComp ( configurator . DeviceLinkTarget , out DeviceLinkSinkComponent ? targetSink ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_deviceLinkSystem . SaveLinks (
args . Session . AttachedEntity ,
configurator . ActiveDeviceLink . Value ,
configurator . DeviceLinkTarget . Value ,
args . Links ,
activeSource ,
targetSink
) ;
UpdateLinkUiState (
uid ,
configurator . ActiveDeviceLink . Value ,
configurator . DeviceLinkTarget . Value ,
activeSource
) ;
2023-05-07 08:07:24 +02:00
}
2023-05-12 00:16:02 +02:00
else if ( TryComp ( configurator . DeviceLinkTarget , out DeviceLinkSourceComponent ? targetSource ) & & TryComp ( configurator . ActiveDeviceLink , out DeviceLinkSinkComponent ? activeSink ) )
2023-05-07 08:07:24 +02:00
{
2023-05-12 00:16:02 +02:00
_deviceLinkSystem . SaveLinks (
args . Session . AttachedEntity ,
configurator . DeviceLinkTarget . Value ,
configurator . ActiveDeviceLink . Value ,
args . Links ,
targetSource ,
activeSink
) ;
UpdateLinkUiState (
uid ,
configurator . DeviceLinkTarget . Value ,
configurator . ActiveDeviceLink . Value ,
targetSource
) ;
2023-05-07 08:07:24 +02:00
}
2022-06-10 03:28:24 +02:00
}
/// <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 ;
2022-09-05 18:22:39 -07:00
var result = DeviceListUpdateResult . NoComponent ;
2022-06-10 03:28:24 +02:00
switch ( args . ButtonKey )
{
case NetworkConfiguratorButtonKey . Set :
2023-06-27 20:03:39 -05:00
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}" ) ;
2022-09-05 18:22:39 -07:00
result = _deviceListSystem . UpdateDeviceList ( component . ActiveDeviceList . Value , new HashSet < EntityUid > ( component . Devices . Values ) ) ;
2022-06-10 03:28:24 +02:00
break ;
case NetworkConfiguratorButtonKey . Add :
2023-06-27 20:03:39 -05:00
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}" ) ;
2022-09-05 18:22:39 -07:00
result = _deviceListSystem . UpdateDeviceList ( component . ActiveDeviceList . Value , new HashSet < EntityUid > ( component . Devices . Values ) , true ) ;
2022-06-10 03:28:24 +02:00
break ;
case NetworkConfiguratorButtonKey . Clear :
2023-06-27 20:03:39 -05:00
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}" ) ;
2022-09-05 18:22:39 -07:00
result = _deviceListSystem . UpdateDeviceList ( component . ActiveDeviceList . Value , new HashSet < EntityUid > ( ) ) ;
2022-06-10 03:28:24 +02:00
break ;
case NetworkConfiguratorButtonKey . Copy :
2023-06-27 20:03:39 -05:00
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}" ) ;
2023-12-21 23:18:40 -05:00
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 ) ;
}
}
2023-05-07 08:07:24 +02:00
UpdateListUiState ( uid , component ) ;
2022-09-05 18:22:39 -07:00
return ;
2022-06-10 03:28:24 +02:00
case NetworkConfiguratorButtonKey . Show :
break ;
}
2022-09-05 18:22:39 -07:00
var resultText = result switch
{
DeviceListUpdateResult . TooManyDevices = > Loc . GetString ( "network-configurator-too-many-devices" ) ,
DeviceListUpdateResult . UpdateOk = > Loc . GetString ( "network-configurator-update-ok" ) ,
_ = > "error"
} ;
2022-12-19 10:41:47 +13:00
_popupSystem . PopupCursor ( Loc . GetString ( resultText ) , args . Session , PopupType . Medium ) ;
2022-09-05 18:22:39 -07:00
_uiSystem . TrySetUiState (
2023-05-12 00:16:02 +02:00
uid ,
2022-09-05 18:22:39 -07:00
NetworkConfiguratorUiKey . Configure ,
new DeviceListUserInterfaceState (
_deviceListSystem . GetDeviceList ( component . ActiveDeviceList . Value )
. Select ( v = > ( v . Key , MetaData ( v . Value ) . EntityName ) ) . ToHashSet ( ) ) ) ;
2022-06-10 03:28:24 +02:00
}
2023-05-07 08:07:24 +02:00
2023-12-21 23:18:40 -05:00
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 ) ;
}
2023-05-07 08:07:24 +02:00
private void OnUiOpenAttempt ( EntityUid uid , NetworkConfiguratorComponent configurator , ActivatableUIOpenAttemptEvent args )
{
if ( configurator . LinkModeActive )
args . Cancel ( ) ;
}
2022-06-10 03:28:24 +02:00
#endregion
}