2023-07-26 21:49:38 +03:00
using Content.Server.MassMedia.Components ;
using Content.Server.PDA.Ringer ;
2023-07-27 22:25:55 +02:00
using Content.Shared.Access.Components ;
using Content.Shared.Access.Systems ;
2023-07-26 21:49:38 +03:00
using Content.Shared.GameTicking ;
2023-07-27 22:25:55 +02:00
using Content.Shared.MassMedia.Components ;
using Content.Shared.MassMedia.Systems ;
using Content.Shared.PDA ;
using Robust.Server.GameObjects ;
2023-07-26 21:49:38 +03:00
using System.Linq ;
2023-08-04 21:17:36 -05:00
using Content.Server.Administration.Logs ;
2023-07-28 22:59:03 +03:00
using Content.Server.CartridgeLoader.Cartridges ;
using Content.Shared.CartridgeLoader ;
using Content.Shared.CartridgeLoader.Cartridges ;
using Content.Server.CartridgeLoader ;
using Robust.Shared.Timing ;
2023-07-31 08:34:22 +03:00
using Content.Server.Popups ;
2023-08-04 21:17:36 -05:00
using Content.Shared.Database ;
2023-07-26 21:49:38 +03:00
namespace Content.Server.MassMedia.Systems ;
public sealed class NewsSystem : EntitySystem
{
2023-07-28 22:59:03 +03:00
[Dependency] private readonly IGameTiming _timing = default ! ;
2023-07-26 21:49:38 +03:00
[Dependency] private readonly UserInterfaceSystem _ui = default ! ;
[Dependency] private readonly RingerSystem _ringer = default ! ;
2023-07-28 22:59:03 +03:00
[Dependency] private readonly CartridgeLoaderSystem ? _cartridgeLoaderSystem = default ! ;
2023-07-31 08:34:22 +03:00
[Dependency] private readonly SharedAudioSystem _audio = default ! ;
[Dependency] private readonly PopupSystem _popup = default ! ;
2023-08-04 21:17:36 -05:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2023-07-28 22:59:03 +03:00
2023-07-27 22:25:55 +02:00
[Dependency] private readonly AccessReaderSystem _accessReader = default ! ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
2023-07-27 22:25:55 +02:00
private readonly List < NewsArticle > _articles = new List < NewsArticle > ( ) ;
2023-07-26 21:49:38 +03:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2023-07-28 22:59:03 +03:00
SubscribeLocalEvent < NewsWriteComponent , NewsWriteShareMessage > ( OnWriteUiShareMessage ) ;
SubscribeLocalEvent < NewsWriteComponent , NewsWriteDeleteMessage > ( OnWriteUiDeleteMessage ) ;
SubscribeLocalEvent < NewsWriteComponent , NewsWriteArticlesRequestMessage > ( OnRequestWriteUiMessage ) ;
SubscribeLocalEvent < NewsReadCartridgeComponent , CartridgeUiReadyEvent > ( OnReadUiReady ) ;
SubscribeLocalEvent < NewsReadCartridgeComponent , CartridgeMessageEvent > ( OnReadUiMessage ) ;
2023-07-26 21:49:38 +03:00
SubscribeLocalEvent < RoundRestartCleanupEvent > ( OnRoundRestart ) ;
}
private void OnRoundRestart ( RoundRestartCleanupEvent ev )
{
2023-07-27 22:25:55 +02:00
_articles ? . Clear ( ) ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
public void ToggleUi ( EntityUid user , EntityUid deviceEnt , NewsWriteComponent ? component )
2023-07-26 21:49:38 +03:00
{
if ( ! Resolve ( deviceEnt , ref component ) )
return ;
if ( ! TryComp < ActorComponent > ( user , out var actor ) )
return ;
2023-07-28 22:59:03 +03:00
_ui . TryToggleUi ( deviceEnt , NewsWriteUiKey . Key , actor . PlayerSession ) ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
public void OnReadUiReady ( EntityUid uid , NewsReadCartridgeComponent component , CartridgeUiReadyEvent args )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
UpdateReadUi ( uid , args . Loader , component ) ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
public void UpdateWriteUi ( EntityUid uid , NewsWriteComponent component )
2023-07-26 21:49:38 +03:00
{
if ( ! _ui . TryGetUi ( uid , NewsWriteUiKey . Key , out _ ) )
return ;
2023-07-28 22:59:03 +03:00
var state = new NewsWriteBoundUserInterfaceState ( _articles . ToArray ( ) , component . ShareAvalible ) ;
2023-07-26 21:49:38 +03:00
_ui . TrySetUiState ( uid , NewsWriteUiKey . Key , state ) ;
}
2023-07-28 22:59:03 +03:00
public void UpdateReadUi ( EntityUid uid , EntityUid loaderUid , NewsReadCartridgeComponent ? component )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
if ( ! Resolve ( uid , ref component ) )
2023-07-26 21:49:38 +03:00
return ;
2023-07-28 22:59:03 +03:00
NewsReadLeafArticle ( component , 0 ) ;
2023-07-27 22:25:55 +02:00
if ( _articles . Any ( ) )
2023-07-28 22:59:03 +03:00
_cartridgeLoaderSystem ? . UpdateCartridgeUiState ( loaderUid , new NewsReadBoundUserInterfaceState ( _articles [ component . ArticleNum ] , component . ArticleNum + 1 , _articles . Count , component . NotificationOn ) ) ;
2023-07-26 21:49:38 +03:00
else
2023-07-28 22:59:03 +03:00
_cartridgeLoaderSystem ? . UpdateCartridgeUiState ( loaderUid , new NewsReadEmptyBoundUserInterfaceState ( component . NotificationOn ) ) ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
private void OnReadUiMessage ( EntityUid uid , NewsReadCartridgeComponent component , CartridgeMessageEvent args )
{
if ( args is not NewsReadUiMessageEvent message )
return ;
if ( message . Action = = NewsReadUiAction . Next )
NewsReadLeafArticle ( component , 1 ) ;
if ( message . Action = = NewsReadUiAction . Prev )
NewsReadLeafArticle ( component , - 1 ) ;
if ( message . Action = = NewsReadUiAction . NotificationSwith )
component . NotificationOn = ! component . NotificationOn ;
UpdateReadUi ( uid , args . LoaderUid , component ) ;
}
public void OnWriteUiShareMessage ( EntityUid uid , NewsWriteComponent component , NewsWriteShareMessage msg )
2023-07-26 21:49:38 +03:00
{
2023-07-27 22:25:55 +02:00
var article = msg . Article ;
var author = msg . Session . AttachedEntity ;
if ( author . HasValue
& & _accessReader . FindAccessItemsInventory ( author . Value , out var items )
& & _accessReader . FindStationRecordKeys ( author . Value , out var stationRecordKeys , items ) )
{
article . AuthorStationRecordKeyIds = stationRecordKeys ;
foreach ( var item in items )
{
// ID Card
if ( TryComp ( item , out IdCardComponent ? id ) )
{
article . Author = id . FullName ;
break ;
}
// PDA
else if ( TryComp ( item , out PdaComponent ? pda )
& & pda . ContainedId ! = null
& & TryComp ( pda . ContainedId , out id ) )
{
article . Author = id . FullName ;
break ;
}
}
}
2023-07-31 08:34:22 +03:00
_audio . PlayPvs ( component . ConfirmSound , uid ) ;
2023-08-04 21:17:36 -05:00
if ( author ! = null )
_adminLogger . Add ( LogType . Chat , LogImpact . Medium , $"{ToPrettyString(author.Value):actor} created news article {article.Name} by {article.Author}: {article.Content}" ) ;
else
_adminLogger . Add ( LogType . Chat , LogImpact . Medium , $"{msg.Session.Name:actor} created news article {article.Name}: {article.Content}" ) ;
2023-07-27 22:25:55 +02:00
_articles . Add ( article ) ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
component . ShareAvalible = false ;
component . NextShare = _timing . CurTime + TimeSpan . FromSeconds ( component . ShareCooldown ) ;
2023-07-26 21:49:38 +03:00
UpdateReadDevices ( ) ;
UpdateWriteDevices ( ) ;
TryNotify ( ) ;
}
2023-07-28 22:59:03 +03:00
public void OnWriteUiDeleteMessage ( EntityUid uid , NewsWriteComponent component , NewsWriteDeleteMessage msg )
2023-07-26 21:49:38 +03:00
{
2023-07-27 22:25:55 +02:00
if ( msg . ArticleNum > _articles . Count )
return ;
2023-08-04 21:17:36 -05:00
var articleDeleter = msg . Session . AttachedEntity ;
if ( CheckDeleteAccess ( _articles [ msg . ArticleNum ] , uid , articleDeleter ) )
2023-07-27 22:25:55 +02:00
{
2023-08-04 21:17:36 -05:00
if ( articleDeleter ! = null )
_adminLogger . Add ( LogType . Chat , LogImpact . Medium , $"{ToPrettyString(articleDeleter.Value):actor} deleted news article {_articles[msg.ArticleNum].Name} by {_articles[msg.ArticleNum].Author}: {_articles[msg.ArticleNum].Content}" ) ;
else
_adminLogger . Add ( LogType . Chat , LogImpact . Medium , $"{msg.Session.Name:actor} created news article {_articles[msg.ArticleNum].Name}: {_articles[msg.ArticleNum].Content}" ) ;
2023-07-27 22:25:55 +02:00
_articles . RemoveAt ( msg . ArticleNum ) ;
2023-07-31 08:34:22 +03:00
_audio . PlayPvs ( component . ConfirmSound , uid ) ;
2023-07-27 22:25:55 +02:00
}
else
2023-07-26 21:49:38 +03:00
{
2023-07-31 08:34:22 +03:00
_popup . PopupEntity ( Loc . GetString ( "news-write-no-access-popup" ) , uid ) ;
_audio . PlayPvs ( component . NoAccessSound , uid ) ;
2023-07-26 21:49:38 +03:00
}
UpdateReadDevices ( ) ;
UpdateWriteDevices ( ) ;
}
2023-07-28 22:59:03 +03:00
public void OnRequestWriteUiMessage ( EntityUid uid , NewsWriteComponent component , NewsWriteArticlesRequestMessage msg )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
UpdateWriteUi ( uid , component ) ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
private void NewsReadLeafArticle ( NewsReadCartridgeComponent component , int leafDir )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
component . ArticleNum + = leafDir ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
if ( component . ArticleNum > = _articles . Count ) component . ArticleNum = 0 ;
if ( component . ArticleNum < 0 ) component . ArticleNum = _articles . Count - 1 ;
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
private void TryNotify ( )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
var query = EntityQueryEnumerator < CartridgeLoaderComponent , RingerComponent > ( ) ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
while ( query . MoveNext ( out var owner , out var comp , out var ringer ) )
2023-07-27 22:25:55 +02:00
{
2023-07-28 22:59:03 +03:00
foreach ( var app in comp . InstalledPrograms )
{
if ( EntityManager . TryGetComponent < NewsReadCartridgeComponent > ( app , out var cartridge ) & & cartridge . NotificationOn )
{
_ringer . RingerPlayRingtone ( owner , ringer ) ;
break ;
}
}
2023-07-27 22:25:55 +02:00
}
2023-07-26 21:49:38 +03:00
}
2023-07-28 22:59:03 +03:00
private void UpdateReadDevices ( )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
var query = EntityQueryEnumerator < CartridgeLoaderComponent > ( ) ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
while ( query . MoveNext ( out var owner , out var comp ) )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
if ( EntityManager . TryGetComponent < NewsReadCartridgeComponent > ( comp . ActiveProgram , out var cartridge ) )
UpdateReadUi ( cartridge . Owner , comp . Owner , cartridge ) ;
2023-07-26 21:49:38 +03:00
}
}
2023-07-28 22:59:03 +03:00
private void UpdateWriteDevices ( )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
var query = EntityQueryEnumerator < NewsWriteComponent > ( ) ;
2023-07-26 21:49:38 +03:00
2023-07-27 22:25:55 +02:00
while ( query . MoveNext ( out var owner , out var comp ) )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
UpdateWriteUi ( owner , comp ) ;
2023-07-26 21:49:38 +03:00
}
}
2023-07-31 08:34:22 +03:00
private bool CheckDeleteAccess ( NewsArticle articleToDelete , EntityUid device , EntityUid ? user )
{
if ( EntityManager . TryGetComponent < AccessReaderComponent > ( device , out var accessReader ) & &
user . HasValue & &
_accessReader . IsAllowed ( user . Value , accessReader ) )
{
return true ;
}
if ( articleToDelete . AuthorStationRecordKeyIds = = null | |
! articleToDelete . AuthorStationRecordKeyIds . Any ( ) )
{
return true ;
}
if ( user . HasValue
& & _accessReader . FindStationRecordKeys ( user . Value , out var recordKeys )
& & recordKeys . Intersect ( articleToDelete . AuthorStationRecordKeyIds ) . Any ( ) )
{
return true ;
}
return false ;
}
2023-07-28 22:59:03 +03:00
public override void Update ( float frameTime )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
base . Update ( frameTime ) ;
2023-07-26 21:49:38 +03:00
2023-07-28 22:59:03 +03:00
var query = EntityQueryEnumerator < NewsWriteComponent > ( ) ;
while ( query . MoveNext ( out var comp ) )
2023-07-26 21:49:38 +03:00
{
2023-07-28 22:59:03 +03:00
if ( comp . ShareAvalible | | _timing . CurTime < comp . NextShare )
continue ;
comp . ShareAvalible = true ;
UpdateWriteUi ( comp . Owner , comp ) ;
2023-07-26 21:49:38 +03:00
}
}
}