2023-10-19 12:34:31 -07:00
using System.Linq ;
using Content.Server.Administration.Logs ;
using Content.Server.CartridgeLoader ;
using Content.Server.CartridgeLoader.Cartridges ;
using Content.Server.GameTicking ;
2023-07-26 21:49:38 +03:00
using Content.Server.MassMedia.Components ;
using Content.Server.PDA.Ringer ;
2023-10-19 12:34:31 -07:00
using Content.Server.Popups ;
using Content.Server.StationRecords.Systems ;
2023-07-27 22:25:55 +02:00
using Content.Shared.Access.Components ;
using Content.Shared.Access.Systems ;
2023-10-19 12:34:31 -07:00
using Content.Shared.CartridgeLoader ;
using Content.Shared.CartridgeLoader.Cartridges ;
using Content.Shared.Database ;
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-11-27 22:12:34 +11:00
using System.Linq ;
using Content.Server.Administration.Logs ;
using Content.Server.CartridgeLoader.Cartridges ;
using Content.Shared.CartridgeLoader ;
using Content.Shared.CartridgeLoader.Cartridges ;
using Content.Server.CartridgeLoader ;
using Content.Server.GameTicking ;
using Robust.Shared.Timing ;
using Content.Server.Popups ;
using Content.Server.StationRecords.Systems ;
using Content.Shared.Database ;
using Robust.Shared.Audio ;
using Robust.Shared.Audio.Systems ;
2023-09-11 09:42:41 +10:00
using Robust.Shared.Containers ;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player ;
2023-10-19 12:34:31 -07:00
using Robust.Shared.Timing ;
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-09-11 09:42:41 +10: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-09-11 09:42:41 +10:00
[Dependency] private readonly GameTicker _ticker = default ! ;
2023-07-27 22:25:55 +02:00
[Dependency] private readonly AccessReaderSystem _accessReader = default ! ;
2023-09-11 09:42:41 +10:00
[Dependency] private readonly StationRecordsSystem _stationRecords = default ! ;
2023-07-26 21:49:38 +03:00
2023-09-11 09:42:41 +10:00
// TODO remove this. Dont store data on systems
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 ;
2023-09-11 09:42:41 +10:00
UpdateReadUi ( uid , GetEntity ( args . LoaderUid ) , component ) ;
2023-07-28 22:59:03 +03:00
}
public void OnWriteUiShareMessage ( EntityUid uid , NewsWriteComponent component , NewsWriteShareMessage msg )
2023-07-26 21:49:38 +03:00
{
2023-09-11 09:42:41 +10:00
// dont blindly trust input from clients.
if ( msg . Session . AttachedEntity is not { } author )
return ;
if ( ! _accessReader . FindAccessItemsInventory ( author , out var items ) )
return ;
2023-07-27 22:25:55 +02:00
2023-09-11 09:42:41 +10:00
if ( ! _accessReader . FindStationRecordKeys ( author , out var stationRecordKeys , items ) )
return ;
string? authorName = null ;
foreach ( var item in items )
2023-07-27 22:25:55 +02:00
{
2023-09-11 09:42:41 +10:00
// ID Card
if ( TryComp ( item , out IdCardComponent ? id ) )
{
authorName = id . FullName ;
break ;
}
2023-07-27 22:25:55 +02:00
2023-09-11 09:42:41 +10:00
if ( TryComp ( item , out PdaComponent ? pda )
& & pda . ContainedId ! = null
& & TryComp ( pda . ContainedId , out id ) )
2023-07-27 22:25:55 +02:00
{
2023-09-11 09:42:41 +10:00
authorName = id . FullName ;
break ;
2023-07-27 22:25:55 +02:00
}
}
2023-09-11 09:42:41 +10:00
NewsArticle article = new NewsArticle
{
Author = authorName ,
Name = ( msg . Name . Length < = 25 ? msg . Name . Trim ( ) : $"{msg.Name.Trim().Substring(0, 25)}..." ) ,
Content = msg . Content ,
ShareTime = _ticker . RoundDuration ( )
2023-07-31 08:34:22 +03:00
2023-09-11 09:42:41 +10:00
} ;
_audio . PlayPvs ( component . ConfirmSound , uid ) ;
_adminLogger . Add ( LogType . Chat , LogImpact . Medium , $"{ToPrettyString(author):actor} created news article {article.Name} by {article.Author}: {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-09-11 09:42:41 +10:00
var query = EntityQueryEnumerator < CartridgeLoaderComponent , RingerComponent , ContainerManagerComponent > ( ) ;
2023-07-26 21:49:38 +03:00
2023-09-11 09:42:41 +10:00
while ( query . MoveNext ( out var uid , out var comp , out var ringer , out var cont ) )
2023-07-27 22:25:55 +02:00
{
2023-11-13 23:43:08 +01:00
if ( ! _cartridgeLoaderSystem . TryGetProgram < NewsReadCartridgeComponent > ( uid , out _ , out var newsReadCartridgeComponent , false , comp , cont )
| | ! newsReadCartridgeComponent . NotificationOn )
2023-09-11 09:42:41 +10:00
continue ;
_ringer . RingerPlayRingtone ( uid , ringer ) ;
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 ) )
2023-10-19 12:34:31 -07:00
UpdateReadUi ( comp . ActiveProgram . Value , 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 & &
2023-09-03 13:05:22 +12:00
_accessReader . IsAllowed ( user . Value , device , accessReader ) )
2023-07-31 08:34:22 +03:00
{
return true ;
}
if ( articleToDelete . AuthorStationRecordKeyIds = = null | |
! articleToDelete . AuthorStationRecordKeyIds . Any ( ) )
{
return true ;
}
2023-09-11 09:42:41 +10:00
var conv = _stationRecords . Convert ( articleToDelete . AuthorStationRecordKeyIds ) ;
2023-07-31 08:34:22 +03:00
if ( user . HasValue
& & _accessReader . FindStationRecordKeys ( user . Value , out var recordKeys )
2023-09-11 09:42:41 +10:00
& & recordKeys . Intersect ( conv ) . Any ( ) )
2023-07-31 08:34:22 +03:00
{
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 > ( ) ;
2023-10-19 12:34:31 -07:00
while ( query . MoveNext ( out var uid , 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 ;
2023-10-19 12:34:31 -07:00
UpdateWriteUi ( uid , comp ) ;
2023-07-26 21:49:38 +03:00
}
}
}