Delta-v/Content.Server/_DV/Administration/EventAlertSystem.cs

154 lines
5.5 KiB
C#

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;
}
}
}