feat: Various Admin QOL features (#5436)
* feat: added lslaws command * feat: add lswatchlisted command * tweak: nicer formatting for lswatchlisted * tweak: nicer formatting for lslaws * feat: lsobjectives lists everyone's objectives if no user specified * feat: mark ghosted players in players tab * docs: add missing DeltaV patch comment * feat: only alert admins if meatspiking player characters * feat: always alert about station explosions, don't spam off-station alerts * feat: stripping alert tweaks * feat: admin alert on low hour latejoin * refactor: forgot to make onspawncomplete non-async, wasn't necessary after all * feat: EORG alerts * feat: getping command * refactor: remove unused imports, format * refactor: early return in onspawncomplete * feat: add coordinate link to eorg destroy alert * tweak: cache watchlist data to avoid db calls, use in lswatchlisted * fix: null-check in OnNoteAdded * feat: watchlist indicator on admin overlay * feat: optionally mark watchlisted in f7 players * feat: refresh admin playerlist data on wl change * fix: update player list after cache write * feat: add tp links to prayer messages * tweak: don't alert when uncuffing self * tweak: lower uncuff other alert impact if mindshielded * docs: add deltav comments to imports * refactor: address review comments * style: deltav comments on same line as change * performance: get metadata only if objectives > 0 * fix: actually check user if explosion gridPos not on station * style: remove extraneous newlines * refactor: use fancy getOrNew method * feat: refresh player list UI if marking pref changed * feat: latejoin alert hours configurable * fix: also list objectives for non-humanoids and dead people
This commit is contained in:
parent
c703999890
commit
3c0d4ab253
|
|
@ -196,8 +196,22 @@ internal sealed class AdminNameOverlay : Overlay
|
|||
// Username
|
||||
color = Color.Yellow;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
currentOffset += lineoffset;
|
||||
var usernameSpace = args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? color : colorDisconnected); // DeltaV - store return value
|
||||
|
||||
// DeltaV - add watchlist suffix START
|
||||
if (playerInfo.Watchlisted)
|
||||
{
|
||||
color = Color.Red;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_fontBold,
|
||||
screenCoordinates + currentOffset + usernameSpace with { Y = 0 },
|
||||
" " + Loc.GetString("admin-overlay-watchlisted-username-suffix"),
|
||||
uiScale,
|
||||
color);
|
||||
}
|
||||
// DeltaV - add watchlist suffix END
|
||||
|
||||
currentOffset += lineoffset; // DeltaV - moved down from username block
|
||||
|
||||
// Playtime
|
||||
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && _overlayPlaytime)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ public sealed partial class PlayerTab : Control
|
|||
private AdminPlayerTabColorOption _playerTabColorSetting;
|
||||
private AdminPlayerTabRoleTypeOption _playerTabRoleSetting;
|
||||
private AdminPlayerTabSymbolOption _playerTabSymbolSetting;
|
||||
private bool _markGhosted; // DeltaV
|
||||
private bool _markWatchlisted; // DeltaV
|
||||
|
||||
public event Action<GUIBoundKeyEventArgs, ListData>? OnEntryKeyBindDown;
|
||||
|
||||
|
|
@ -51,6 +53,8 @@ public sealed partial class PlayerTab : Control
|
|||
_config.OnValueChanged(CCVars.AdminPlayerTabRoleSetting, RoleSettingChanged, true);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerTabColorSetting, ColorSettingChanged, true);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerTabSymbolSetting, SymbolSettingChanged, true);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerTabMarkGhosted, MarkGhostedChanged, true); // DeltaV
|
||||
_config.OnValueChanged(CCVars.AdminPlayerTabMarkWatchlisted, MarkWatchlistedChanged, true); // DeltaV
|
||||
|
||||
OverlayButton.OnPressed += OverlayButtonPressed;
|
||||
ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed;
|
||||
|
|
@ -66,6 +70,20 @@ public sealed partial class PlayerTab : Control
|
|||
RefreshPlayerList(_adminSystem.PlayerList);
|
||||
}
|
||||
|
||||
// DeltaV - mark ghosted, watchlisted START
|
||||
private void MarkGhostedChanged(bool value)
|
||||
{
|
||||
_markGhosted = value;
|
||||
RefreshPlayerList(_players);
|
||||
}
|
||||
|
||||
private void MarkWatchlistedChanged(bool value)
|
||||
{
|
||||
_markWatchlisted = value;
|
||||
RefreshPlayerList(_players);
|
||||
}
|
||||
// DeltaV - mark ghosted, watchlisted END
|
||||
|
||||
#region Antag Overlay
|
||||
|
||||
private void OverlayEnabled()
|
||||
|
|
@ -152,8 +170,25 @@ public sealed partial class PlayerTab : Control
|
|||
|
||||
UpdateHeaderSymbols();
|
||||
|
||||
SearchList.PopulateList(sortedPlayers.Select(info => new PlayerListData(info,
|
||||
$"{info.Username} {info.CharacterName} {info.IdentityName} {info.StartingJob}"))
|
||||
SearchList.PopulateList(sortedPlayers.Select(info =>
|
||||
{
|
||||
// DeltaV - additions START
|
||||
var filteringStringAdditions = "";
|
||||
if (_markGhosted && info.Ghost)
|
||||
{
|
||||
filteringStringAdditions += " (G)";
|
||||
}
|
||||
|
||||
if (_markWatchlisted && info.Watchlisted)
|
||||
{
|
||||
filteringStringAdditions += " (WL)";
|
||||
}
|
||||
// DeltaV - additions END
|
||||
|
||||
return new PlayerListData(info,
|
||||
$"{info.Username} {info.CharacterName} {info.IdentityName} {info.StartingJob}" +
|
||||
filteringStringAdditions); // DeltaV - append filteringStringAdditions
|
||||
})
|
||||
.ToList());
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +202,10 @@ public sealed partial class PlayerTab : Control
|
|||
new StyleBoxFlat(button.Index % 2 == 0 ? _altColor : _defaultColor),
|
||||
_playerTabColorSetting,
|
||||
_playerTabRoleSetting,
|
||||
_playerTabSymbolSetting);
|
||||
_playerTabSymbolSetting,
|
||||
_markGhosted, // DeltaV - Add _markGhosted
|
||||
_markWatchlisted // DeltaV - Add _markWatchlisted
|
||||
);
|
||||
button.AddChild(entry);
|
||||
button.ToolTip = $"{player.Username}, {player.CharacterName}, {player.IdentityName}, {player.StartingJob}";
|
||||
button.StyleClasses.Clear();
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
|||
StyleBoxFlat styleBoxFlat,
|
||||
AdminPlayerTabColorOption colorOption,
|
||||
AdminPlayerTabRoleTypeOption roleSetting,
|
||||
AdminPlayerTabSymbolOption symbolSetting)
|
||||
AdminPlayerTabSymbolOption symbolSetting,
|
||||
bool markGhosted, // DeltaV - Add markGhosted
|
||||
bool markWatchlisted // DeltaV - Add markWatchlisted
|
||||
)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
|
@ -73,6 +76,17 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
|||
if (player.IdentityName != player.CharacterName)
|
||||
CharacterLabel.Text += $" [{player.IdentityName}]";
|
||||
|
||||
// DeltaV - Mark ghosted/watchlisted players START
|
||||
if (player.Ghost && markGhosted)
|
||||
{
|
||||
CharacterLabel.Text = $"(G) {CharacterLabel.Text}";
|
||||
}
|
||||
if (player.Watchlisted && markWatchlisted)
|
||||
{
|
||||
CharacterLabel.Text = $"(WL) {CharacterLabel.Text}";
|
||||
}
|
||||
// DeltaV - Mark ghosted/watchlisted players END
|
||||
|
||||
var roletype = RoleTypeLabel.Text = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
|
||||
var subtype = roles.GetRoleSubtypeLabel(rolePrototype?.Name ?? RoleTypePrototype.FallbackName, player.Subtype);
|
||||
switch (roleSetting)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
<ui:OptionDropDown Name="DropDownPlayerTabSymbolSetting" Title="{Loc 'ui-options-admin-player-tab-symbol-setting'}" />
|
||||
<ui:OptionDropDown Name="DropDownPlayerTabRoleSetting" Title="{Loc 'ui-options-admin-player-tab-role-setting'}" />
|
||||
<ui:OptionDropDown Name="DropDownPlayerTabColorSetting" Title="{Loc 'ui-options-admin-player-tab-color-setting'}" />
|
||||
<CheckBox Name="EnablePlayerTabMarkGhosted" Text="{Loc 'ui-options-admin-player-tab-mark-ghosted'}" ToolTip="{Loc 'ui-options-admin-player-tab-mark-ghosted-tooltip'}" /> <!-- DeltaV - Add MarkGhosted -->
|
||||
<CheckBox Name="EnablePlayerTabMarkWatchlisted" Text="{Loc 'ui-options-admin-player-tab-mark-watchlisted'}" ToolTip="{Loc 'ui-options-admin-player-tab-mark-watchlisted-tooltip'}" /> <!-- DeltaV - Add MarkWatchlisted -->
|
||||
<Label Text="{Loc 'ui-options-admin-logs-title'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<ui:OptionColorSlider Name="ColorSliderLogsHighlight" Title="{Loc 'ui-options-admin-logs-highlight-color'}" />
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ public sealed partial class AdminOptionsTab : Control
|
|||
Control.AddOptionDropDown(CCVars.AdminPlayerTabSymbolSetting, DropDownPlayerTabSymbolSetting, playerTabSymbolSettings);
|
||||
Control.AddOptionDropDown(CCVars.AdminPlayerTabRoleSetting, DropDownPlayerTabRoleSetting, playerTabRoleSettings);
|
||||
Control.AddOptionDropDown(CCVars.AdminPlayerTabColorSetting, DropDownPlayerTabColorSetting, playerTabColorSettings);
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerTabMarkGhosted, EnablePlayerTabMarkGhosted); // DeltaV
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerTabMarkWatchlisted, EnablePlayerTabMarkWatchlisted); // DeltaV
|
||||
|
||||
Control.AddOptionDropDown(CCVars.AdminOverlayAntagFormat, DropDownOverlayAntagFormat, antagFormats);
|
||||
Control.AddOptionDropDown(CCVars.AdminOverlaySymbolStyle, DropDownOverlayAntagSymbol, antagSymbolStyles);
|
||||
|
|
|
|||
|
|
@ -495,7 +495,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
|||
/// <summary>
|
||||
/// Creates a list of tpto command links of the given players
|
||||
/// </summary>
|
||||
private bool CreateTpLinks(List<(NetEntity NetEnt, string CharacterName)> players, out string outString)
|
||||
// DeltaV - Make public static
|
||||
public static bool CreateTpLinks(List<(NetEntity NetEnt, string CharacterName)> players, out string outString)
|
||||
{
|
||||
outString = string.Empty;
|
||||
|
||||
|
|
@ -519,7 +520,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
|||
/// <summary>
|
||||
/// Creates a list of toto command links for the given map coordinates.
|
||||
/// </summary>
|
||||
private bool CreateCordLinks(List<MapCoordinates> cords, out string outString)
|
||||
// DeltaV - Make public static
|
||||
public static bool CreateCordLinks(List<MapCoordinates> cords, out string outString)
|
||||
{
|
||||
outString = string.Empty;
|
||||
|
||||
|
|
@ -543,7 +545,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
|||
/// <summary>
|
||||
/// Escape the given text to not allow breakouts of the cmdlink tags.
|
||||
/// </summary>
|
||||
private string EscapeText(string text)
|
||||
// DeltaV - Make public static
|
||||
public static string EscapeText(string text)
|
||||
{
|
||||
return FormattedMessage.EscapeText(text).Replace("\"", "\\\"").Replace("'", "\\'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
using System.Collections.ObjectModel; // DeltaV - Admin QOL
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Commands;
|
||||
using Content.Server.Administration.Systems; // DeltaV - Admin QOL
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.EUI;
|
||||
using Content.Shared.Administration.Notes; // DeltaV - Admin QOL
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network; // DeltaV - Admin QOL
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
|
@ -19,13 +23,79 @@ public sealed class AdminNotesSystem : EntitySystem
|
|||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly EuiManager _euis = default!;
|
||||
[Dependency] private readonly AdminSystem _admin = default!; // DeltaV
|
||||
|
||||
// DeltaV - watchlist cache defs START
|
||||
// For use by other systems
|
||||
// Used by lswatchlisted command to avoid querying database for every connected user every time it's invoked.
|
||||
public ReadOnlyDictionary<NetUserId, List<SharedAdminNote>> ConnectedPlayerWatchlists => _connectedPlayerWatchlists.AsReadOnly();
|
||||
private readonly Dictionary<NetUserId, List<SharedAdminNote>> _connectedPlayerWatchlists = new();
|
||||
// DeltaV - watchlist cache defs END
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<GetVerbsEvent<Verb>>(AddVerbs);
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
|
||||
// DeltaV - track watchlist changes START
|
||||
_notes.NoteAdded += OnNoteAdded;
|
||||
_notes.NoteModified += OnNoteModified;
|
||||
_notes.NoteDeleted += OnNoteDeleted;
|
||||
// DeltaV - track watchlist changes END
|
||||
}
|
||||
|
||||
// DeltaV - track watchlist changes START
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_notes.NoteAdded -= OnNoteAdded;
|
||||
_notes.NoteModified -= OnNoteModified;
|
||||
_notes.NoteDeleted -= OnNoteDeleted;
|
||||
}
|
||||
|
||||
private void OnNoteAdded(SharedAdminNote note)
|
||||
{
|
||||
if (note.NoteType != NoteType.Watchlist)
|
||||
return;
|
||||
|
||||
var notes = _connectedPlayerWatchlists.GetOrNew(note.Player);
|
||||
notes.Add(note);
|
||||
|
||||
if (_playerManager.TryGetSessionById(note.Player, out var session))
|
||||
_admin.UpdatePlayerList(session);
|
||||
}
|
||||
|
||||
private void OnNoteModified(SharedAdminNote note)
|
||||
{
|
||||
if (note.NoteType != NoteType.Watchlist)
|
||||
return;
|
||||
|
||||
var modifiedIndex = _connectedPlayerWatchlists[note.Player].FindIndex(n => n.Id == note.Id);
|
||||
if (modifiedIndex != -1)
|
||||
_connectedPlayerWatchlists[note.Player][modifiedIndex] = note;
|
||||
|
||||
if (_playerManager.TryGetSessionById(note.Player, out var session))
|
||||
_admin.UpdatePlayerList(session);
|
||||
}
|
||||
|
||||
private void OnNoteDeleted(SharedAdminNote note)
|
||||
{
|
||||
if (note.NoteType != NoteType.Watchlist)
|
||||
return;
|
||||
|
||||
var deletedIndex = _connectedPlayerWatchlists[note.Player].FindIndex(n => n.Id == note.Id);
|
||||
if (deletedIndex != -1)
|
||||
_connectedPlayerWatchlists[note.Player].RemoveAt(deletedIndex);
|
||||
|
||||
if (_connectedPlayerWatchlists[note.Player].Count == 0)
|
||||
_connectedPlayerWatchlists.Remove(note.Player);
|
||||
|
||||
if (_playerManager.TryGetSessionById(note.Player, out var session))
|
||||
_admin.UpdatePlayerList(session);
|
||||
}
|
||||
// DeltaV - track watchlist changes END
|
||||
|
||||
private void AddVerbs(GetVerbsEvent<Verb> ev)
|
||||
{
|
||||
if (EntityManager.GetComponentOrNull<ActorComponent>(ev.User) is not {PlayerSession: var user} ||
|
||||
|
|
@ -53,12 +123,25 @@ public sealed class AdminNotesSystem : EntitySystem
|
|||
|
||||
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
// DeltaV - clear watchlist cache on disconnect START
|
||||
if (e.NewStatus == SessionStatus.Disconnected)
|
||||
{
|
||||
_connectedPlayerWatchlists.Remove(e.Session.UserId);
|
||||
return;
|
||||
}
|
||||
// DeltaV - clear watchlist cache on disconnect END
|
||||
|
||||
if (e.NewStatus != SessionStatus.InGame)
|
||||
return;
|
||||
|
||||
var messages = await _notes.GetNewMessages(e.Session.UserId);
|
||||
var watchlists = await _notes.GetActiveWatchlists(e.Session.UserId);
|
||||
|
||||
// DeltaV - write to cache START
|
||||
if (watchlists.Count != 0)
|
||||
_connectedPlayerWatchlists[e.Session.UserId] = watchlists.Select(r => r.ToShared()).ToList();
|
||||
// DeltaV - write to cache END
|
||||
|
||||
if (!_playerManager.TryGetPlayerData(e.Session.UserId, out var playerData))
|
||||
{
|
||||
Log.Error($"Could not get player data for ID {e.Session.UserId}");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Administration.Notes; // DeltaV - Admin QOL
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Hands.Systems;
|
||||
|
|
@ -12,6 +13,7 @@ using Content.Shared.Administration.Events;
|
|||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Forensics.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Ghost; // DeltaV - Admin QOL
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Inventory;
|
||||
|
|
@ -55,6 +57,7 @@ public sealed class AdminSystem : EntitySystem
|
|||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly StationRecordsSystem _stationRecords = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly AdminNotesSystem _notes = default!; // DeltaV
|
||||
|
||||
private readonly Dictionary<NetUserId, PlayerInfo> _playerList = new();
|
||||
|
||||
|
|
@ -220,12 +223,14 @@ public sealed class AdminSystem : EntitySystem
|
|||
var entityName = string.Empty;
|
||||
var identityName = string.Empty;
|
||||
var sortWeight = 0;
|
||||
var ghost = false; // DeltaV
|
||||
|
||||
// Visible (identity) name can be different from real name
|
||||
if (session?.AttachedEntity != null)
|
||||
{
|
||||
entityName = Comp<MetaDataComponent>(session.AttachedEntity.Value).EntityName;
|
||||
identityName = Identity.Name(session.AttachedEntity.Value, EntityManager);
|
||||
ghost = HasComp<GhostComponent>(session.AttachedEntity.Value); // DeltaV
|
||||
}
|
||||
|
||||
var antag = false;
|
||||
|
|
@ -252,6 +257,7 @@ public sealed class AdminSystem : EntitySystem
|
|||
|
||||
// Connection status and playtime
|
||||
var connected = session != null && session.Status is SessionStatus.Connected or SessionStatus.InGame;
|
||||
var watchlisted = connected && _notes.ConnectedPlayerWatchlists.ContainsKey(session!.UserId); // DeltaV
|
||||
|
||||
// Start with the last available playtime data
|
||||
var cachedInfo = GetCachedPlayerInfo(data.UserId);
|
||||
|
|
@ -277,7 +283,10 @@ public sealed class AdminSystem : EntitySystem
|
|||
data.UserId,
|
||||
connected,
|
||||
_roundActivePlayers.Contains(data.UserId),
|
||||
overallPlaytime);
|
||||
overallPlaytime,
|
||||
ghost, // DeltaV - Add ghost
|
||||
watchlisted // DeltaV - Add watchlisted
|
||||
);
|
||||
}
|
||||
|
||||
private void OnPanicBunkerChanged(bool enabled)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server._DV.Administration; // DeltaV - Admin QOL
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Systems;
|
||||
|
|
@ -83,6 +84,8 @@ namespace Content.Server.Destructible
|
|||
|
||||
if (args.Origin != null)
|
||||
{
|
||||
RaiseLocalEvent(uid, new EventAlertSystem.BrokenWithOriginEvent(args.Origin.Value), true); // DeltaV
|
||||
|
||||
AdminLogger.Add(LogType.Damaged,
|
||||
logImpact,
|
||||
$"{ToPrettyString(args.Origin.Value):actor} caused {ToPrettyString(uid):subject} to trigger [{triggeredBehaviors}]");
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Content.Server.Atmos.EntitySystems;
|
|||
using Content.Server.Destructible;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NPC.Pathfinding;
|
||||
using Content.Server.Station.Systems; // DeltaV - Admin QOL
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.CCVar;
|
||||
|
|
@ -54,6 +55,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
|||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammableSystem = default!;
|
||||
[Dependency] private readonly DestructibleSystem _destructibleSystem = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!; // DeltaV
|
||||
|
||||
private EntityQuery<FlammableComponent> _flammableQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
|
@ -246,19 +248,47 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
|||
if (!addLog)
|
||||
return;
|
||||
|
||||
// DeltaV - check if on station START
|
||||
string? stationName = null;
|
||||
var station = _stationSystem.GetOwningStation(gridPos?.EntityId);
|
||||
// just in case: is the user on station?
|
||||
if (station is null && user is not null)
|
||||
{
|
||||
station = _stationSystem.GetOwningStation(user);
|
||||
}
|
||||
|
||||
if (station is not null)
|
||||
{
|
||||
if (_stationSystem.TryGetNetEntity(station, out var stationNetEnt))
|
||||
{
|
||||
stationName = _stationSystem.GetStationNames().Find(x => x.Entity == stationNetEnt).Name;
|
||||
}
|
||||
}
|
||||
// DeltaV - check if on station END
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High,
|
||||
$"{ToPrettyString(uid):entity} exploded ({typeId}) at Pos:{(posFound ? $"{gridPos:coordinates}" : "[Grid or Map not found]")} with intensity {totalIntensity} slope {slope}");
|
||||
_adminLogger.Add(LogType.Explosion, station is not null ? LogImpact.Extreme : LogImpact.High, // DeltaV - Set to Extreme if onStation (always alert), add station name if available
|
||||
$"{ToPrettyString(uid):entity} exploded ({typeId}) at {(stationName != null ? $"{stationName} " : "")}Pos:{(posFound ? $"{gridPos:coordinates}" : "[Grid or Map not found]")} with intensity {totalIntensity} slope {slope}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var alertMinExplosionIntensity = _cfg.GetCVar(CCVars.AdminAlertExplosionMinIntensity);
|
||||
var logImpact = (alertMinExplosionIntensity > -1 && totalIntensity >= alertMinExplosionIntensity)
|
||||
? LogImpact.Extreme
|
||||
: LogImpact.High;
|
||||
: LogImpact.Medium; // DeltaV - If false, Medium instead of High
|
||||
|
||||
// DeltaV - Set to Extreme if onStation (always alert) START
|
||||
if (station is not null)
|
||||
logImpact = LogImpact.Extreme;
|
||||
// DeltaV - Set to Extreme if onStation (always alert) END
|
||||
|
||||
if (posFound)
|
||||
_adminLogger.Add(LogType.Explosion, logImpact, $"{ToPrettyString(user.Value):user} caused {ToPrettyString(uid):entity} to explode ({typeId}) at Pos:{gridPos:coordinates} with intensity {totalIntensity} slope {slope}");
|
||||
{
|
||||
_adminLogger.Add(LogType.Explosion,
|
||||
logImpact,
|
||||
$"{ToPrettyString(user.Value):user} caused {ToPrettyString(uid):entity} to explode ({typeId}) at {(stationName != null ? $"{stationName} " : "")}Pos:{gridPos:coordinates} with intensity {totalIntensity} slope {slope}"); // DeltaV - Add stationName to log message if available
|
||||
}
|
||||
else
|
||||
_adminLogger.Add(LogType.Explosion, logImpact, $"{ToPrettyString(user.Value):user} caused {ToPrettyString(uid):entity} to explode ({typeId}) at Pos:[Grid or Map not found] with intensity {totalIntensity} slope {slope}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Content.Server.Administration;
|
|||
using Content.Shared.Administration;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Content.Shared.Players;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Player;
|
||||
|
|
@ -23,7 +24,14 @@ namespace Content.Server.Objectives.Commands
|
|||
if (args.Length > 0)
|
||||
_players.TryGetSessionByUsername(args[0], out player);
|
||||
else
|
||||
player = shell.Player;
|
||||
{
|
||||
// DeltaV - Print everyone's objectives START
|
||||
// previously: player = shell.Player
|
||||
// implemented like this to make it easier to rip out later
|
||||
ListAllObjectives(shell);
|
||||
return;
|
||||
// DeltaV - Print everyone's objectives END
|
||||
}
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
|
|
@ -62,6 +70,45 @@ namespace Content.Server.Objectives.Commands
|
|||
}
|
||||
}
|
||||
|
||||
// DeltaV - Added function START
|
||||
private void ListAllObjectives(IConsoleShell shell)
|
||||
{
|
||||
var minds = _entities.EntityQueryEnumerator<MindComponent>();
|
||||
while (minds.MoveNext(out var mindId, out var mindComp))
|
||||
{
|
||||
ICommonSession? player = null;
|
||||
if (mindComp.OwnedEntity is not null)
|
||||
{
|
||||
_players.TryGetSessionByEntity(mindComp.OwnedEntity.Value, out player);
|
||||
}
|
||||
|
||||
if (mindComp.Objectives.Count > 0)
|
||||
{
|
||||
_entities.TryGetComponent<MetaDataComponent>(mindComp.OwnedEntity, out var metaData);
|
||||
shell.WriteMarkup($"\n[bold]{metaData?.EntityName}[/bold] ({player?.Name ?? "No player attached?"})");
|
||||
|
||||
var objectivesSystem = _entities.System<SharedObjectivesSystem>();
|
||||
var objectives = mindComp.Objectives;
|
||||
|
||||
for (var i = 0; i < objectives.Count; i++)
|
||||
{
|
||||
var info = objectivesSystem.GetInfo(objectives[i], mindId);
|
||||
if (info == null)
|
||||
{
|
||||
shell.WriteLine($"- [{i}] {objectives[i]} - INVALID");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var progress = (int) (info.Value.Progress * 100f);
|
||||
shell.WriteLine($"- [{i}] {objectives[i]} ({info.Value.Title}) ({progress}%)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DeltaV - Added function END
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Server._DV.Administration; // DeltaV - Admin QOL
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Bible.Components;
|
||||
|
|
@ -24,6 +25,7 @@ public sealed class PrayerSystem : EntitySystem
|
|||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly QuickDialogSystem _quickDialog = default!;
|
||||
[Dependency] private readonly EventAlertSystem _eventAlert = default!; // DeltaV
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
|
@ -105,6 +107,7 @@ public sealed class PrayerSystem : EntitySystem
|
|||
_popupSystem.PopupEntity(Loc.GetString(comp.SentMessage), sender.AttachedEntity.Value, sender, PopupType.Medium);
|
||||
|
||||
_chatManager.SendAdminAnnouncement($"{Loc.GetString(comp.NotificationPrefix)} <{sender.Name}>: {message}");
|
||||
_eventAlert.SendLinks(sender.AttachedEntity); // DeltaV - send tp links for prayers
|
||||
_adminLogger.Add(LogType.AdminMessage, LogImpact.Low, $"{ToPrettyString(sender.AttachedEntity.Value):player} sent prayer ({Loc.GetString(comp.NotificationPrefix)}): {message}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server._DV.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class GetPingCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
public override string Command => "getping";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1 || !_player.TryGetSessionByUsername(args[0], out var session))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-getping-err"));
|
||||
return;
|
||||
}
|
||||
|
||||
shell.WriteLine($"{session.Name}'s ping: {session.Ping}");
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
return args.Length == 1
|
||||
? CompletionResult.FromHintOptions(CompletionHelper.SessionNames(), "username")
|
||||
: CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server._DV.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class ListLawsCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
|
||||
public override string Command => "lslaws";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length > 1)
|
||||
{
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args.Length)
|
||||
{
|
||||
case 0:
|
||||
foreach (var (ent, lawProvider) in _entityManager.AllEntities<SiliconLawProviderComponent>())
|
||||
{
|
||||
WriteLawReport(shell, ent, lawProvider);
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
if (!_player.TryGetSessionByUsername(args[0], out var session) ||
|
||||
!_entityManager.TryGetComponent<SiliconLawProviderComponent>(session.AttachedEntity,
|
||||
out var provider))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-lslaws-error-bad-player"));
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLawReport(shell, session.AttachedEntity.Value, provider);
|
||||
break;
|
||||
default:
|
||||
shell.WriteLine(Help);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteLawReport(IConsoleShell shell, EntityUid ent, SiliconLawProviderComponent lawProvider)
|
||||
{
|
||||
shell.WriteLine("");
|
||||
_entityManager.TryGetComponent<MetaDataComponent>(ent, out var metaData);
|
||||
var entityName = metaData?.EntityName;
|
||||
|
||||
shell.WriteMarkup(_player.TryGetSessionByEntity(ent, out var session)
|
||||
? $"[bold]{entityName}[/bold] ({ent.Id}, [color=red]{session.Name}[/color], subverted: {lawProvider.Subverted})"
|
||||
: $"[bold]{entityName}[/bold] ({ent.Id}, subverted: {lawProvider.Subverted})");
|
||||
|
||||
shell.WriteLine($"Base Lawset: {lawProvider.Laws.Id}");
|
||||
if (lawProvider.Lawset is { } lawset)
|
||||
{
|
||||
foreach (var siliconLaw in lawset.Laws)
|
||||
{
|
||||
shell.WriteLine($"{siliconLaw.Order}: {Loc.GetString(siliconLaw.LawString)}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteLine("Unable to retrieve laws.");
|
||||
}
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
return args.Length == 1
|
||||
? CompletionResult.FromOptions(CompletionHelper.SessionNames())
|
||||
: CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using System.Globalization;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Notes;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server._DV.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class ListWatchlistedCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly AdminNotesSystem _notes = default!;
|
||||
|
||||
public override string Command => "lswatchlisted";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (_notes.ConnectedPlayerWatchlists.Count == 0)
|
||||
{
|
||||
shell.WriteLine("No watchlisted players online.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (playerId, records) in _notes.ConnectedPlayerWatchlists)
|
||||
{
|
||||
if (!_player.TryGetSessionById(playerId, out var sessionData))
|
||||
return;
|
||||
|
||||
shell.WriteMarkup($"\n[bold]{sessionData.Name}[/bold]\n");
|
||||
foreach (var record in records)
|
||||
{
|
||||
shell.WriteLine("");
|
||||
record.CreatedAt.Deconstruct(out var date, out _);
|
||||
shell.WriteLine($"Created: {date.ToString("O", CultureInfo.InvariantCulture)}");
|
||||
if (record.ExpiryTime is { } expirationTime)
|
||||
{
|
||||
expirationTime.Deconstruct(out var expirationDate, out _);
|
||||
shell.WriteLine($"Expires: {expirationDate.ToString("O", CultureInfo.InvariantCulture)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteLine("Expires: PERMANENT");
|
||||
}
|
||||
|
||||
foreach (var line in record.Message.Split('\n', StringSplitOptions.TrimEntries))
|
||||
{
|
||||
shell.WriteLine($"> {line}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Players.PlayTimeTracking;
|
||||
using Content.Shared._DV.CCVars;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Trigger;
|
||||
using Content.Shared.Trigger.Components;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._DV.Administration;
|
||||
|
||||
public sealed class EventAlertSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly PlayTimeTrackingManager _playTime = default!;
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
|
||||
private double _lateJoinAlertMaxHours;
|
||||
private HashSet<EntityUid> _eorgAlerted = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
||||
SubscribeLocalEvent<DestructibleComponent, BrokenWithOriginEvent>(OnBrokenWithOrigin);
|
||||
SubscribeLocalEvent<TimerTriggerComponent, ActiveTimerTriggerEvent>(OnTimerTrigger);
|
||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRunLevelChanged);
|
||||
SubscribeLocalEvent<ActorComponent, AttackedEvent>(OnPlayerAttacked);
|
||||
|
||||
_config.OnValueChanged(DCCVars.LateJoinAlertMaxHours, OnMaxHoursCvarChanged, true); // DeltaV
|
||||
}
|
||||
|
||||
private void OnMaxHoursCvarChanged(double hours)
|
||||
{
|
||||
_lateJoinAlertMaxHours = hours;
|
||||
}
|
||||
|
||||
private void OnTimerTrigger(Entity<TimerTriggerComponent> ent, ref ActiveTimerTriggerEvent args)
|
||||
{
|
||||
if (_gameTicker.RunLevel != GameRunLevel.PostRound || args.User is not { } user)
|
||||
return;
|
||||
|
||||
if (_eorgAlerted.Add(user))
|
||||
{
|
||||
AlertWithLink(
|
||||
$"[EORG] {ToPrettyString(user):player} activated timer trigger of {ToPrettyString(ent):item}.",
|
||||
user);
|
||||
}
|
||||
}
|
||||
|
||||
// Alert if player starts destroying stuff at EOR.
|
||||
// Only sent if it's the first instance of possible EORG for that player to avoid spam.
|
||||
private void OnBrokenWithOrigin(Entity<DestructibleComponent> target, ref BrokenWithOriginEvent ev)
|
||||
{
|
||||
if (_gameTicker.RunLevel != GameRunLevel.PostRound || !HasComp<ActorComponent>(ev.Origin))
|
||||
return;
|
||||
|
||||
if (_eorgAlerted.Add(ev.Origin))
|
||||
{
|
||||
AlertWithLink($"[EORG] {ToPrettyString(ev.Origin):player} destroyed {ToPrettyString(target):entity}.",
|
||||
ev.Origin);
|
||||
}
|
||||
}
|
||||
|
||||
// Alert if player starts attacking others at EOR.
|
||||
// Only sent if it's the first instance of possible EORG for that player to avoid spam.
|
||||
private void OnPlayerAttacked(Entity<ActorComponent> targetPlayer, ref AttackedEvent ev)
|
||||
{
|
||||
if (_gameTicker.RunLevel != GameRunLevel.PostRound)
|
||||
return;
|
||||
|
||||
if (_eorgAlerted.Add(ev.User))
|
||||
{
|
||||
AlertWithLink(
|
||||
$"[EORG] {ToPrettyString(ev.User)} attacked {ToPrettyString(targetPlayer):player} using {(ev.Used == ev.User ? "Hands" : ToPrettyString(ev.Used))}.",
|
||||
ev.User);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRunLevelChanged(GameRunLevelChangedEvent ev)
|
||||
{
|
||||
_eorgAlerted.Clear();
|
||||
}
|
||||
|
||||
// Alert when overall playtime is lower than this and player latejoins.
|
||||
// Useful for raiders that first-join and then wait in Lobby for a while to slip in or briefly join to get a bit of playtime.
|
||||
private void OnSpawnComplete(PlayerSpawnCompleteEvent ev)
|
||||
{
|
||||
if (!ev.LateJoin)
|
||||
return;
|
||||
|
||||
var playtimeHours = _playTime.GetOverallPlaytime(ev.Player).TotalHours;
|
||||
if (playtimeHours < _lateJoinAlertMaxHours)
|
||||
{
|
||||
AlertWithLink($"New player {ev.Player.Name} [{playtimeHours:0.#} hours] joined the round.", ev.Mob);
|
||||
}
|
||||
}
|
||||
|
||||
public void AlertWithLink(string message, EntityUid playerEnt, MapCoordinates? coords = null)
|
||||
{
|
||||
_chat.SendAdminAlert(message);
|
||||
SendLinks(playerEnt, coords);
|
||||
}
|
||||
|
||||
public void SendLinks(EntityUid? playerEnt = null, MapCoordinates? mapCoords = null)
|
||||
{
|
||||
List<MapCoordinates> coords = new();
|
||||
if (playerEnt is not null)
|
||||
{
|
||||
var originName = "Actor";
|
||||
if (TryComp(playerEnt, out MetaDataComponent? meta))
|
||||
{
|
||||
originName = meta.EntityName;
|
||||
}
|
||||
|
||||
if (_entity.GetNetEntity(playerEnt) is { } netEnt &&
|
||||
AdminLogManager.CreateTpLinks([(netEnt, originName)], out var tpLinks))
|
||||
{
|
||||
_chat.SendAdminAlertNoFormatOrEscape(tpLinks);
|
||||
coords.Add(_transform.GetMapCoordinates(playerEnt.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (mapCoords is not null && mapCoords.Value != MapCoordinates.Nullspace)
|
||||
{
|
||||
coords.Add(mapCoords.Value);
|
||||
}
|
||||
if (coords.Count != 0 && AdminLogManager.CreateCordLinks(coords, out var coordLinks))
|
||||
{
|
||||
_chat.SendAdminAlertNoFormatOrEscape(coordLinks);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BrokenWithOriginEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Origin;
|
||||
|
||||
public BrokenWithOriginEvent(EntityUid origin)
|
||||
{
|
||||
Origin = origin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,10 @@ public sealed record PlayerInfo(
|
|||
NetUserId SessionId,
|
||||
bool Connected,
|
||||
bool ActiveThisRound,
|
||||
TimeSpan? OverallPlaytime)
|
||||
TimeSpan? OverallPlaytime,
|
||||
bool Ghost, // DeltaV - Add Ghost
|
||||
bool Watchlisted // DeltaV - Add Watchlisted
|
||||
)
|
||||
{
|
||||
private string? _playtimeString;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ public sealed partial class CCVars
|
|||
/// Minimum explosion intensity to create an admin alert message. -1 to disable the alert.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> AdminAlertExplosionMinIntensity =
|
||||
CVarDef.Create("admin.alert.explosion_min_intensity", 60, CVar.SERVERONLY);
|
||||
CVarDef.Create("admin.alert.explosion_min_intensity", -1, CVar.SERVERONLY); // DeltaV - disable, previously set to 60
|
||||
|
||||
/// <summary>
|
||||
/// Minimum particle accelerator strength to create an admin alert message.
|
||||
|
|
|
|||
|
|
@ -93,6 +93,21 @@ public sealed partial class CCVars
|
|||
public static readonly CVarDef<string> AdminPlayerTabRoleSetting =
|
||||
CVarDef.Create("ui.admin_player_tab_role", "Subtype", CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
// DeltaV - Additions START
|
||||
|
||||
/// <summary>
|
||||
/// Whether to prepend "(G)" to player character names in the players tab
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> AdminPlayerTabMarkGhosted =
|
||||
CVarDef.Create("ui.admin_player_tab_mark_ghosted", true, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to prepend "(WL)" to player character names in the players tab
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> AdminPlayerTabMarkWatchlisted =
|
||||
CVarDef.Create("ui.admin_player_tab_mark_watchlisted", true, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
// DeltaV - Additions END
|
||||
|
||||
/// <summary>
|
||||
/// Determines how antagonist status/roletype is displayed. Based on AdminOverlayAntagSymbolStyles enum
|
||||
/// Off: No symbol is shown.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ using Content.Shared.Inventory;
|
|||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Mindshield.Components; // DeltaV - Admin QOL
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Movement.Pulling.Events;
|
||||
using Content.Shared.Popups;
|
||||
|
|
@ -665,7 +666,11 @@ namespace Content.Shared.Cuffs
|
|||
if (!_doAfter.TryStartDoAfter(doAfterEventArgs))
|
||||
return;
|
||||
|
||||
_adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(user):player} is trying to uncuff {ToPrettyString(target):subject}");
|
||||
// DeltaV - Conditional Impact START
|
||||
var isMindShielded = HasComp<MindShieldComponent>(user);
|
||||
// Only alert if new user tries to uncuff someone else and if they aren't mindshielded, stops spam during escape attempts or for cadets. LogImpact previously always High.
|
||||
_adminLog.Add(LogType.Action, isOwner || isMindShielded ? LogImpact.Medium : LogImpact.High, $"{ToPrettyString(user):player} is trying to uncuff {ToPrettyString(target):subject}");
|
||||
// DeltaV - Conditional impact END
|
||||
|
||||
var popupText = user == target.Owner
|
||||
? "cuffable-component-start-uncuffing-self-observer"
|
||||
|
|
@ -765,7 +770,7 @@ namespace Content.Shared.Cuffs
|
|||
{
|
||||
_popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-by-other-success-message",
|
||||
("otherName", Identity.Name(user.Value, EntityManager, user))), target, target);
|
||||
_adminLog.Add(LogType.Action, LogImpact.High,
|
||||
_adminLog.Add(LogType.Action, HasComp<MindShieldComponent>(user) ? LogImpact.Medium : LogImpact.High, // DeltaV - make impact conditional, previously always high
|
||||
$"{ToPrettyString(user):player} has successfully uncuffed {ToPrettyString(target):player}");
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ using Content.Shared.Interaction.Events;
|
|||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Kitchen.Components;
|
||||
using Content.Shared.Mind.Components; // DeltaV - Admin QOL
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.SSDIndicator; // DeltaV - Admin QOL
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
|
@ -240,12 +242,30 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem
|
|||
args.Target.Value,
|
||||
ent);
|
||||
|
||||
// normally medium severity, but for humanoids high severity, so new players get relay'd to admin alerts.
|
||||
var logSeverity = HasComp<HumanoidAppearanceComponent>(args.Target) ? LogImpact.High : LogImpact.Medium;
|
||||
// DeltaV - Replace logSeverity START
|
||||
var logSeverity = LogImpact.Medium;
|
||||
|
||||
// Extreme impact if SSD indicator comp is present on target (as of writing only regular player characters have it), always alerting
|
||||
if (HasComp<SSDIndicatorComponent>(args.Target.Value))
|
||||
{
|
||||
logSeverity = LogImpact.Extreme;
|
||||
}
|
||||
|
||||
var hasMind = false;
|
||||
// Extreme impact if a mind is attached to the target, always alerting
|
||||
if (TryComp<MindContainerComponent>(args.Target.Value, out var mindContainer))
|
||||
{
|
||||
if (mindContainer.HasMind)
|
||||
{
|
||||
hasMind = true;
|
||||
logSeverity = LogImpact.Extreme;
|
||||
}
|
||||
}
|
||||
// DeltaV - Replace logSeverity END
|
||||
|
||||
_logger.Add(LogType.Action,
|
||||
logSeverity,
|
||||
$"{ToPrettyString(args.User):user} put {ToPrettyString(args.Target):target} on the {ToPrettyString(ent):spike}");
|
||||
$"{ToPrettyString(args.User):user} put {ToPrettyString(args.Target):target}{(hasMind ? " (MIND ATTACHED)" : "")} on the {ToPrettyString(ent):spike}"); // DeltaV - Add hasMind indicator
|
||||
|
||||
_audioSystem.PlayPredicted(ent.Comp.SpikeSound, ent, args.User);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Content.Shared.Interaction.Events;
|
|||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.SSDIndicator; // DeltaV - Admin QOL
|
||||
using Content.Shared.Strip.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Utility;
|
||||
|
|
@ -36,6 +37,9 @@ public abstract class SharedStrippableSystem : EntitySystem
|
|||
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
private readonly string[] _highImpactOnStrip = ["id", "belt", "back"]; // DeltaV - high impact on player, key items
|
||||
private readonly string[] _extremeImpactOnStrip = ["jumpsuit"]; // DeltaV - people shouldn't be stripping each others clothes off
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
|
@ -351,7 +355,29 @@ public abstract class SharedStrippableSystem : EntitySystem
|
|||
RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc.
|
||||
|
||||
_handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: !stealth);
|
||||
_adminLogger.Add(LogType.Stripping, LogImpact.High, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot");
|
||||
|
||||
// DeltaV - LogImpact Additions START
|
||||
// Previously High by default. Stop chat spam from searches in Sec. Somebody with bad intentions is likely to strip from the specified slots.
|
||||
var logImpact = LogImpact.Medium;
|
||||
if (_highImpactOnStrip.Contains(slot.ToLower()))
|
||||
{
|
||||
logImpact = LogImpact.High;
|
||||
}
|
||||
|
||||
if (_extremeImpactOnStrip.Contains(slot.ToLower()))
|
||||
{
|
||||
logImpact = LogImpact.Extreme;
|
||||
}
|
||||
|
||||
var isSsd = false;
|
||||
if (TryComp<SSDIndicatorComponent>(target, out var ssdIndicator) && ssdIndicator.IsSSD)
|
||||
{
|
||||
isSsd = true;
|
||||
logImpact = LogImpact.Extreme;
|
||||
}
|
||||
// DeltaV - LogImpact Additions END
|
||||
|
||||
_adminLogger.Add(LogType.Stripping, logImpact, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {(isSsd ? "[SSD] " : "")}{ToPrettyString(target):target}'s {slot} slot"); // DeltaV - replace default LogImpact, insert SSD indicator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -565,8 +591,8 @@ public abstract class SharedStrippableSystem : EntitySystem
|
|||
|
||||
_handsSystem.TryDrop(target, item, checkActionBlocker: false);
|
||||
_handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: !stealth, handsComp: user.Comp);
|
||||
_adminLogger.Add(LogType.Stripping, LogImpact.High, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands");
|
||||
|
||||
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); // DeltaV - Lower LogImpact to Medium, if someone is stripping from hands, the item was probably being offered to them. If not, the target is much more likely to notice.
|
||||
// Hand update will trigger strippable update.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,6 +202,12 @@ public sealed partial class DCCVars
|
|||
public static readonly CVarDef<string> DiscordReplyColor =
|
||||
CVarDef.Create("admin.discord_reply_color", string.Empty, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of hours that will trigger an admin alert on late join.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<double> LateJoinAlertMaxHours =
|
||||
CVarDef.Create("admin.alerts.latejoin_max_hours", 2.0, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to disable the preset selecting test rule from running. Should be disabled in production. DeltaV specific, attached to Impstation Secret concurrent feature.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Commands
|
||||
cmd-lslaws-desc = Lists laws of all lawbound entities or a specific player if specified
|
||||
cmd-lslaws-help = lslaws [username]
|
||||
cmd-lslaws-error-bad-player = Unable to find lawbound entity attached to that user.
|
||||
|
||||
cmd-lswatchlisted-desc = Prints an overview of all connected players with watchlists
|
||||
cmd-lswatchlisted-help = lswatchlisted
|
||||
|
||||
cmd-getping-desc = Prints the specified player's current ping
|
||||
cmd-getping-help = getping <username>
|
||||
cmd-getping-err = Unable to find specified player
|
||||
|
||||
# UI
|
||||
ui-options-admin-player-tab-mark-ghosted = Mark ghosted players
|
||||
ui-options-admin-player-tab-mark-ghosted-tooltip = Ghosts will have a "(G)" added to their character names (e.g. "(G) Glip-Glub")
|
||||
|
||||
ui-options-admin-player-tab-mark-watchlisted = Mark watchlisted players
|
||||
ui-options-admin-player-tab-mark-watchlisted-tooltip = Watchlisted players will have a "(WL)" added to their character names (e.g. "(WL) Confusion Bot 2007")
|
||||
|
|
@ -0,0 +1 @@
|
|||
admin-overlay-watchlisted-username-suffix = [WL]
|
||||
Loading…
Reference in New Issue