2021-10-12 00:11:09 -05:00
using System.Threading ;
2021-10-05 14:29:03 +11:00
using Content.Server.Administration.Commands ;
using Content.Server.Administration.Managers ;
using Content.Server.Administration.UI ;
2021-10-29 13:40:15 +01:00
using Content.Server.Chemistry.Components.SolutionManager ;
2021-11-08 17:22:42 +13:00
using Content.Server.Chemistry.EntitySystems ;
2021-10-05 14:29:03 +11:00
using Content.Server.Configurable ;
using Content.Server.Disposal.Tube.Components ;
using Content.Server.EUI ;
2021-11-09 21:24:35 +01:00
using Content.Server.Explosion.EntitySystems ;
2021-10-05 14:29:03 +11:00
using Content.Server.Ghost.Roles ;
using Content.Server.Mind.Commands ;
using Content.Server.Mind.Components ;
using Content.Server.Players ;
2022-02-19 22:16:49 +03:00
using Content.Server.Xenoarchaeology.XenoArtifacts ;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components ;
2021-10-05 14:29:03 +11:00
using Content.Shared.Administration ;
2021-10-12 00:11:09 -05:00
using Content.Shared.Body.Components ;
2021-11-28 14:56:53 +01:00
using Content.Shared.Database ;
2021-11-08 17:22:42 +13:00
using Content.Shared.GameTicking ;
2021-10-05 14:29:03 +11:00
using Content.Shared.Interaction.Helpers ;
2021-12-30 22:56:10 +01:00
using Content.Shared.Inventory ;
2021-10-05 14:29:03 +11:00
using Content.Shared.Popups ;
using Content.Shared.Verbs ;
using Robust.Server.Console ;
using Robust.Server.GameObjects ;
2021-11-08 17:22:42 +13:00
using Robust.Server.Player ;
2021-12-14 01:19:34 +01:00
using Robust.Shared.Console ;
2021-10-12 00:11:09 -05:00
using Robust.Shared.Timing ;
2022-03-31 18:22:38 +13:00
using static Content . Shared . Configurable . SharedConfigurationComponent ;
2021-10-12 00:11:09 -05:00
using Timer = Robust . Shared . Timing . Timer ;
2021-10-05 14:29:03 +11:00
namespace Content.Server.Administration
{
/// <summary>
/// System to provide various global admin/debug verbs
/// </summary>
2022-02-16 00:23:23 -07:00
public sealed class AdminVerbSystem : EntitySystem
2021-10-05 14:29:03 +11:00
{
[Dependency] private readonly IConGroupController _groupController = default ! ;
2021-12-14 01:19:34 +01:00
[Dependency] private readonly IConsoleHost _console = default ! ;
2021-10-05 14:29:03 +11:00
[Dependency] private readonly IAdminManager _adminManager = default ! ;
2021-10-12 00:11:09 -05:00
[Dependency] private readonly IGameTiming _gameTiming = default ! ;
2021-10-05 14:29:03 +11:00
[Dependency] private readonly EuiManager _euiManager = default ! ;
2022-04-01 15:39:26 +13:00
[Dependency] private readonly ExplosionSystem _explosionSystem = default ! ;
2021-10-05 14:29:03 +11:00
[Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default ! ;
2022-02-19 22:16:49 +03:00
[Dependency] private readonly ArtifactSystem _artifactSystem = default ! ;
2022-03-31 18:22:38 +13:00
[Dependency] private readonly UserInterfaceSystem _uiSystem = default ! ;
2021-10-12 00:11:09 -05:00
2021-11-08 17:22:42 +13:00
private readonly Dictionary < IPlayerSession , EditSolutionsEui > _openSolutionUis = new ( ) ;
2021-10-05 14:29:03 +11:00
public override void Initialize ( )
{
2022-02-10 15:30:59 +13:00
SubscribeLocalEvent < GetVerbsEvent < Verb > > ( AddAdminVerbs ) ;
SubscribeLocalEvent < GetVerbsEvent < Verb > > ( AddDebugVerbs ) ;
2021-11-08 17:22:42 +13:00
SubscribeLocalEvent < RoundRestartCleanupEvent > ( Reset ) ;
SubscribeLocalEvent < SolutionContainerManagerComponent , SolutionChangedEvent > ( OnSolutionChanged ) ;
2021-10-05 14:29:03 +11:00
}
2022-02-10 15:30:59 +13:00
private void AddAdminVerbs ( GetVerbsEvent < Verb > args )
2021-12-14 01:19:34 +01:00
{
if ( ! EntityManager . TryGetComponent < ActorComponent ? > ( args . User , out var actor ) )
return ;
var player = actor . PlayerSession ;
2022-01-03 01:07:33 -08:00
if ( _adminManager . IsAdmin ( player ) )
2021-12-14 01:19:34 +01:00
{
2022-01-03 01:07:33 -08:00
if ( TryComp ( args . Target , out ActorComponent ? targetActor ) )
{
// AdminHelp
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "ahelp-verb-get-data-text" ) ;
verb . Category = VerbCategory . Admin ;
verb . IconTexture = "/Textures/Interface/gavel.svg.192dpi.png" ;
verb . Act = ( ) = >
_console . RemoteExecuteCommand ( player , $"openahelp \" { targetActor . PlayerSession . UserId } \ "" ) ;
verb . Impact = LogImpact . Low ;
args . Verbs . Add ( verb ) ;
2022-02-16 00:23:23 -07:00
2022-02-11 19:01:37 -07:00
// Freeze
var frozen = HasComp < AdminFrozenComponent > ( args . Target ) ;
args . Verbs . Add ( new Verb
{
Priority = - 1 , // This is just so it doesn't change position in the menu between freeze/unfreeze.
Text = frozen
? Loc . GetString ( "admin-verbs-unfreeze" )
: Loc . GetString ( "admin-verbs-freeze" ) ,
Category = VerbCategory . Admin ,
IconTexture = "/Textures/Interface/VerbIcons/snow.svg.192dpi.png" ,
Act = ( ) = >
{
if ( frozen )
RemComp < AdminFrozenComponent > ( args . Target ) ;
else
EnsureComp < AdminFrozenComponent > ( args . Target ) ;
} ,
Impact = LogImpact . Medium ,
} ) ;
2022-01-03 01:07:33 -08:00
}
2022-02-19 22:16:49 +03:00
// XenoArcheology
if ( TryComp < ArtifactComponent > ( args . Target , out var artifact ) )
{
// make artifact always active (by adding timer trigger)
args . Verbs . Add ( new Verb ( )
{
Text = Loc . GetString ( "artifact-verb-make-always-active" ) ,
Category = VerbCategory . Admin ,
Act = ( ) = > EntityManager . AddComponent < ArtifactTimerTriggerComponent > ( args . Target ) ,
Disabled = EntityManager . HasComponent < ArtifactTimerTriggerComponent > ( args . Target ) ,
Impact = LogImpact . High
} ) ;
// force to activate artifact ignoring timeout
args . Verbs . Add ( new Verb ( )
{
Text = Loc . GetString ( "artifact-verb-activate" ) ,
Category = VerbCategory . Admin ,
Act = ( ) = > _artifactSystem . ForceActivateArtifact ( args . Target , component : artifact ) ,
Impact = LogImpact . High
} ) ;
}
2022-01-03 01:07:33 -08:00
// TeleportTo
args . Verbs . Add ( new Verb
{
Text = Loc . GetString ( "admin-verbs-teleport-to" ) ,
Category = VerbCategory . Admin ,
IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png" ,
Act = ( ) = > _console . ExecuteCommand ( player , $"tpto {args.Target}" ) ,
Impact = LogImpact . Low
} ) ;
// TeleportHere
args . Verbs . Add ( new Verb
{
Text = Loc . GetString ( "admin-verbs-teleport-here" ) ,
Category = VerbCategory . Admin ,
IconTexture = "/Textures/Interface/VerbIcons/close.svg.192dpi.png" ,
Act = ( ) = > _console . ExecuteCommand ( player , $"tpto {args.Target} {args.User}" ) ,
Impact = LogImpact . Low
} ) ;
2021-12-14 01:19:34 +01:00
}
2022-01-03 01:07:33 -08:00
// Artillery
2021-12-14 01:19:34 +01:00
if ( _adminManager . HasAdminFlag ( player , AdminFlags . Fun ) )
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "explode-verb-get-data-text" ) ;
verb . Category = VerbCategory . Admin ;
verb . Act = ( ) = >
{
2022-04-01 15:39:26 +13:00
var coords = Transform ( args . Target ) . MapPosition ;
Timer . Spawn ( _gameTiming . TickPeriod ,
2022-04-05 19:22:35 +12:00
( ) = > _explosionSystem . QueueExplosion ( coords , ExplosionSystem . DefaultExplosionPrototypeId , 4 , 1 , 2 , maxTileBreak : 0 ) , // it gibs, damage doesn't need to be high.
2022-04-01 15:39:26 +13:00
CancellationToken . None ) ;
2021-12-14 01:19:34 +01:00
if ( TryComp ( args . Target , out SharedBodyComponent ? body ) )
{
body . Gib ( ) ;
}
} ;
verb . Impact = LogImpact . Extreme ; // if you're just outright killing a person, I guess that deserves to be extreme?
2022-01-13 06:28:17 -08:00
verb . ConfirmationPopup = true ;
2021-12-14 01:19:34 +01:00
args . Verbs . Add ( verb ) ;
}
}
2022-02-10 15:30:59 +13:00
private void AddDebugVerbs ( GetVerbsEvent < Verb > args )
2021-10-05 14:29:03 +11:00
{
2021-12-05 18:09:01 +01:00
if ( ! EntityManager . TryGetComponent < ActorComponent ? > ( args . User , out var actor ) )
2021-10-05 14:29:03 +11:00
return ;
var player = actor . PlayerSession ;
// Delete verb
if ( _groupController . CanCommand ( player , "deleteentity" ) )
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "delete-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
2021-10-28 18:21:19 +13:00
verb . IconTexture = "/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png" ;
2021-12-05 18:09:01 +01:00
verb . Act = ( ) = > EntityManager . DeleteEntity ( args . Target ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ;
2022-01-13 06:28:17 -08:00
verb . ConfirmationPopup = true ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
// Rejuvenate verb
if ( _groupController . CanCommand ( player , "rejuvenate" ) )
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "rejuvenate-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/rejuvenate.svg.192dpi.png" ;
verb . Act = ( ) = > RejuvenateCommand . PerformRejuvenate ( args . Target ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
// Control mob verb
if ( _groupController . CanCommand ( player , "controlmob" ) & &
args . User ! = args . Target & &
2021-12-05 18:09:01 +01:00
EntityManager . HasComponent < MindComponent > ( args . User ) & &
EntityManager . TryGetComponent < MindComponent ? > ( args . Target , out var targetMind ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "control-mob-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
// TODO VERB ICON control mob icon
verb . Act = ( ) = >
{
2021-12-03 15:53:09 +01:00
player . ContentData ( ) ? . Mind ? . TransferTo ( args . Target , ghostCheckOverride : true ) ;
2021-10-05 14:29:03 +11:00
} ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . High ;
2022-01-13 06:28:17 -08:00
verb . ConfirmationPopup = true ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
// Make Sentient verb
if ( _groupController . CanCommand ( player , "makesentient" ) & &
args . User ! = args . Target & &
2021-12-05 18:09:01 +01:00
! EntityManager . HasComponent < MindComponent > ( args . Target ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "make-sentient-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/sentient.svg.192dpi.png" ;
2021-12-03 15:53:09 +01:00
verb . Act = ( ) = > MakeSentientCommand . MakeSentient ( args . Target , EntityManager ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
// Set clothing verb
if ( _groupController . CanCommand ( player , "setoutfit" ) & &
2021-12-05 18:09:01 +01:00
EntityManager . HasComponent < InventoryComponent > ( args . Target ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "set-outfit-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png" ;
verb . Act = ( ) = > _euiManager . OpenEui ( new SetOutfitEui ( args . Target ) , player ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
// In range unoccluded verb
if ( _groupController . CanCommand ( player , "inrangeunoccluded" ) )
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "in-range-unoccluded-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/information.svg.192dpi.png" ;
verb . Act = ( ) = >
{
var message = args . User . InRangeUnOccluded ( args . Target )
? Loc . GetString ( "in-range-unoccluded-verb-on-activate-not-occluded" )
: Loc . GetString ( "in-range-unoccluded-verb-on-activate-occluded" ) ;
args . Target . PopupMessage ( args . User , message ) ;
} ;
args . Verbs . Add ( verb ) ;
}
// Get Disposal tube direction verb
if ( _groupController . CanCommand ( player , "tubeconnections" ) & &
2021-12-05 18:09:01 +01:00
EntityManager . TryGetComponent < IDisposalTubeComponent ? > ( args . Target , out var tube ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "tube-direction-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/information.svg.192dpi.png" ;
verb . Act = ( ) = > tube . PopupDirections ( args . User ) ;
args . Verbs . Add ( verb ) ;
}
// Make ghost role verb
if ( _groupController . CanCommand ( player , "makeghostrole" ) & &
2021-12-05 18:09:01 +01:00
! ( EntityManager . GetComponentOrNull < MindComponent > ( args . Target ) ? . HasMind ? ? false ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "make-ghost-role-verb-get-data-text" ) ;
verb . Category = VerbCategory . Debug ;
// TODO VERB ICON add ghost icon
// Where is the national park service icon for haunted forests?
2021-12-03 15:53:09 +01:00
verb . Act = ( ) = > _ghostRoleSystem . OpenMakeGhostRoleEui ( player , args . Target ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
if ( _groupController . CanAdminMenu ( player ) & &
2021-12-05 18:09:01 +01:00
EntityManager . TryGetComponent < ConfigurationComponent ? > ( args . Target , out var config ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
verb . Text = Loc . GetString ( "configure-verb-get-data-text" ) ;
verb . IconTexture = "/Textures/Interface/VerbIcons/settings.svg.192dpi.png" ;
verb . Category = VerbCategory . Debug ;
2022-03-31 18:22:38 +13:00
verb . Act = ( ) = > _uiSystem . TryOpen ( args . Target , ConfigurationUiKey . Key , actor . PlayerSession ) ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
2021-11-08 17:22:42 +13:00
// Add verb to open Solution Editor
if ( _groupController . CanCommand ( player , "addreagent" ) & &
2021-12-05 18:09:01 +01:00
EntityManager . HasComponent < SolutionContainerManagerComponent > ( args . Target ) )
2021-10-05 14:29:03 +11:00
{
Verb verb = new ( ) ;
2021-11-08 17:22:42 +13:00
verb . Text = Loc . GetString ( "edit-solutions-verb-get-data-text" ) ;
2021-10-05 14:29:03 +11:00
verb . Category = VerbCategory . Debug ;
verb . IconTexture = "/Textures/Interface/VerbIcons/spill.svg.192dpi.png" ;
2021-12-03 15:53:09 +01:00
verb . Act = ( ) = > OpenEditSolutionsEui ( player , args . Target ) ;
2021-11-23 23:00:16 +13:00
verb . Impact = LogImpact . Medium ; // maybe high depending on WHAT reagents they add...
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
}
2021-11-08 17:22:42 +13:00
#region SolutionsEui
private void OnSolutionChanged ( EntityUid uid , SolutionContainerManagerComponent component , SolutionChangedEvent args )
{
foreach ( var eui in _openSolutionUis . Values )
{
if ( eui . Target = = uid )
eui . StateDirty ( ) ;
}
}
public void OpenEditSolutionsEui ( IPlayerSession session , EntityUid uid )
{
if ( session . AttachedEntity = = null )
return ;
if ( _openSolutionUis . ContainsKey ( session ) )
_openSolutionUis [ session ] . Close ( ) ;
var eui = _openSolutionUis [ session ] = new EditSolutionsEui ( uid ) ;
_euiManager . OpenEui ( eui , session ) ;
eui . StateDirty ( ) ;
}
public void OnEditSolutionsEuiClosed ( IPlayerSession session )
{
_openSolutionUis . Remove ( session , out var eui ) ;
}
private void Reset ( RoundRestartCleanupEvent ev )
{
_openSolutionUis . Clear ( ) ;
}
#endregion
2021-10-05 14:29:03 +11:00
}
}