2022-08-14 07:57:25 +02:00
using Content.Server.Configurable ;
using Content.Server.DeviceNetwork ;
using Content.Server.DeviceNetwork.Components ;
using Content.Server.DeviceNetwork.Systems ;
using Content.Server.Disposal.Unit.EntitySystems ;
using Content.Server.Power.Components ;
2024-02-11 14:19:45 +11:00
using Content.Shared.DeviceNetwork ;
2022-08-14 07:57:25 +02:00
using Content.Shared.Disposal ;
using Content.Shared.Interaction ;
using Robust.Server.GameObjects ;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player ;
2022-08-14 07:57:25 +02:00
namespace Content.Server.Disposal.Mailing ;
public sealed class MailingUnitSystem : EntitySystem
{
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default ! ;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
private const string MailTag = "mail" ;
private const string TagConfigurationKey = "tag" ;
private const string NetTag = "tag" ;
private const string NetSrc = "src" ;
private const string NetTarget = "target" ;
private const string NetCmdSent = "mail_sent" ;
private const string NetCmdRequest = "get_mailer_tag" ;
private const string NetCmdResponse = "mailer_tag" ;
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < MailingUnitComponent , ComponentInit > ( OnComponentInit ) ;
SubscribeLocalEvent < MailingUnitComponent , DeviceNetworkPacketEvent > ( OnPacketReceived ) ;
2022-09-11 16:50:59 +10:00
SubscribeLocalEvent < MailingUnitComponent , BeforeDisposalFlushEvent > ( OnBeforeFlush ) ;
2022-08-14 07:57:25 +02:00
SubscribeLocalEvent < MailingUnitComponent , ConfigurationSystem . ConfigurationUpdatedEvent > ( OnConfigurationUpdated ) ;
SubscribeLocalEvent < MailingUnitComponent , ActivateInWorldEvent > ( HandleActivate ) ;
2022-09-11 16:50:59 +10:00
SubscribeLocalEvent < MailingUnitComponent , DisposalUnitUIStateUpdatedEvent > ( OnDisposalUnitUIStateChange ) ;
2022-08-14 07:57:25 +02:00
SubscribeLocalEvent < MailingUnitComponent , TargetSelectedMessage > ( OnTargetSelected ) ;
}
private void OnComponentInit ( EntityUid uid , MailingUnitComponent component , ComponentInit args )
{
UpdateTargetList ( uid , component ) ;
}
private void OnPacketReceived ( EntityUid uid , MailingUnitComponent component , DeviceNetworkPacketEvent args )
{
if ( ! args . Data . TryGetValue ( DeviceNetworkConstants . Command , out string? command ) | | ! IsPowered ( uid ) )
return ;
switch ( command )
{
case NetCmdRequest :
SendTagRequestResponse ( uid , args , component . Tag ) ;
break ;
case NetCmdResponse when args . Data . TryGetValue ( NetTag , out string? tag ) :
//Add the received tag request response to the list of targets
2023-01-19 03:56:45 +01:00
component . TargetList . Add ( tag ) ;
2023-06-21 07:31:19 -07:00
UpdateUserInterface ( uid , component ) ;
2022-08-14 07:57:25 +02:00
break ;
}
}
/// <summary>
/// Sends the given tag as a response to a <see cref="NetCmdRequest"/> if it's not null
/// </summary>
private void SendTagRequestResponse ( EntityUid uid , DeviceNetworkPacketEvent args , string? tag )
{
if ( tag = = null )
return ;
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = NetCmdResponse ,
[NetTag] = tag
} ;
_deviceNetworkSystem . QueuePacket ( uid , args . Address , payload , args . Frequency ) ;
}
/// <summary>
/// Prevents the unit from flushing if no target is selected
/// </summary>
2022-09-11 16:50:59 +10:00
private void OnBeforeFlush ( EntityUid uid , MailingUnitComponent component , BeforeDisposalFlushEvent args )
2022-08-14 07:57:25 +02:00
{
if ( string . IsNullOrEmpty ( component . Target ) )
{
args . Cancel ( ) ;
return ;
}
args . Tags . Add ( MailTag ) ;
args . Tags . Add ( component . Target ) ;
BroadcastSentMessage ( uid , component ) ;
}
/// <summary>
/// Broadcast that a mail was sent including the src and target tags
/// </summary>
private void BroadcastSentMessage ( EntityUid uid , MailingUnitComponent component , DeviceNetworkComponent ? device = null )
{
if ( string . IsNullOrEmpty ( component . Tag ) | | string . IsNullOrEmpty ( component . Target ) | | ! Resolve ( uid , ref device ) )
return ;
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = NetCmdSent ,
[NetSrc] = component . Tag ,
[NetTarget] = component . Target
} ;
2023-08-21 22:18:30 +01:00
_deviceNetworkSystem . QueuePacket ( uid , null , payload , null , null , device ) ;
2022-08-14 07:57:25 +02:00
}
/// <summary>
/// Clears the units target list and broadcasts a <see cref="NetCmdRequest"/>.
/// The target list will then get populated with <see cref="NetCmdResponse"/> responses from all active mailing units on the same grid
/// </summary>
private void UpdateTargetList ( EntityUid uid , MailingUnitComponent component , DeviceNetworkComponent ? device = null )
{
if ( ! Resolve ( uid , ref device , false ) )
return ;
var payload = new NetworkPayload
{
[DeviceNetworkConstants.Command] = NetCmdRequest
} ;
component . TargetList . Clear ( ) ;
2023-08-21 22:18:30 +01:00
_deviceNetworkSystem . QueuePacket ( uid , null , payload , null , null , device ) ;
2022-08-14 07:57:25 +02:00
}
/// <summary>
/// Gets called when the units tag got updated
/// </summary>
private void OnConfigurationUpdated ( EntityUid uid , MailingUnitComponent component , ConfigurationSystem . ConfigurationUpdatedEvent args )
{
var configuration = args . Configuration . Config ;
if ( ! configuration . ContainsKey ( TagConfigurationKey ) | | configuration [ TagConfigurationKey ] = = string . Empty )
{
component . Tag = null ;
return ;
}
component . Tag = configuration [ TagConfigurationKey ] ;
2023-06-21 07:31:19 -07:00
UpdateUserInterface ( uid , component ) ;
2022-08-14 07:57:25 +02:00
}
private void HandleActivate ( EntityUid uid , MailingUnitComponent component , ActivateInWorldEvent args )
{
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
{
return ;
}
args . Handled = true ;
UpdateTargetList ( uid , component ) ;
2023-06-21 07:31:19 -07:00
if ( _userInterfaceSystem . TryGetUi ( uid , MailingUnitUiKey . Key , out var bui ) )
_userInterfaceSystem . OpenUi ( bui , actor . PlayerSession ) ;
2022-08-14 07:57:25 +02:00
}
/// <summary>
/// Gets called when the disposal unit components ui state changes. This is required because the mailing unit requires a disposal unit component and overrides its ui
/// </summary>
2022-09-11 16:50:59 +10:00
private void OnDisposalUnitUIStateChange ( EntityUid uid , MailingUnitComponent component , DisposalUnitUIStateUpdatedEvent args )
2022-08-14 07:57:25 +02:00
{
component . DisposalUnitInterfaceState = args . State ;
2023-06-21 07:31:19 -07:00
UpdateUserInterface ( uid , component ) ;
2022-08-14 07:57:25 +02:00
}
2023-06-21 07:31:19 -07:00
private void UpdateUserInterface ( EntityUid uid , MailingUnitComponent component )
2022-08-14 07:57:25 +02:00
{
if ( component . DisposalUnitInterfaceState = = null )
return ;
var state = new MailingUnitBoundUserInterfaceState ( component . DisposalUnitInterfaceState , component . Target , component . TargetList , component . Tag ) ;
2023-06-21 07:31:19 -07:00
if ( _userInterfaceSystem . TryGetUi ( uid , MailingUnitUiKey . Key , out var bui ) )
2023-09-11 09:42:41 +10:00
_userInterfaceSystem . SetUiState ( bui , state ) ;
2022-08-14 07:57:25 +02:00
}
private void OnTargetSelected ( EntityUid uid , MailingUnitComponent component , TargetSelectedMessage args )
{
2023-06-21 07:31:19 -07:00
component . Target = args . Target ;
UpdateUserInterface ( uid , component ) ;
2022-08-14 07:57:25 +02:00
}
/// <summary>
/// Checks if the unit is powered if an <see cref="ApcPowerReceiverComponent"/> is present
/// </summary>
/// <returns>True if the power receiver component is powered or not present</returns>
private bool IsPowered ( EntityUid uid , ApcPowerReceiverComponent ? powerReceiver = null )
{
if ( Resolve ( uid , ref powerReceiver ) & & ! powerReceiver . Powered )
return false ;
return true ;
}
}