Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
misandrie authored Jan 6, 2025
1 parent e196b0b commit 11cec21
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Robust.Shared.Network;
using Robust.Shared.Player;

namespace Content.Server._Goobstation.PlayerListener;

/// <summary>
/// Stores data about players, listens even.
/// </summary>
[RegisterComponent]
public sealed partial class PlayerListenerComponent : Component
{
[ViewVariables(VVAccess.ReadOnly)]
public readonly HashSet<NetUserId> UserIds = [];
}
106 changes: 106 additions & 0 deletions Content.Server/_Goobstation/PlayerListener/RageQuitNotifySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Content.Server.Chat.Managers;
using Content.Server.GameTicking.Events;
using Content.Shared._Goobstation.CCVar;
using Content.Shared.Chat;
using Content.Shared.Mobs;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Timing;

namespace Content.Server._Goobstation.PlayerListener;

/// <summary>
/// Records and notifies when a user has rage quit the game.
///
/// To qualify as a rage quit, the next things should be true
/// 1. The character the user was playing has hit a damage threshold
/// 2. The damage threshold has degraded the state of the mob (Alive->Crit, Crit->Dead, Alive->Dead)
/// 2. The player has left the game in X or less amount of seconds after condition 2 became true
/// </summary>
public sealed class RageQuitNotifySystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IServerNetManager _network = default!;
[Dependency] private readonly IChatManager _chat = default!;

private EntityUid _ent;
private bool _notify = true;
private float _timer = 5f;

public override void Initialize()
{
base.Initialize();
Subs.CVar(_cfg, GoobCVars.PlayerRageQuitNotify, value => _notify = value, invokeImmediately: true);
Subs.CVar(_cfg, GoobCVars.PlayerRageQuitTimeThreshold, value => _timer = value, invokeImmediately: true);

SubscribeLocalEvent<RoundStartingEvent>(OnRoundStarting);
SubscribeLocalEvent<ActorComponent, MobStateChangedEvent>(OnActorMobStateChanged);

_network.Disconnect += OnDisconnect;
}

public override void Shutdown()
{
_network.Disconnect -= OnDisconnect;
}

private void OnRoundStarting(RoundStartingEvent args)
{
_ent = Spawn(null, MapCoordinates.Nullspace);
AddComp<PlayerListenerComponent>(_ent);
}

private void OnDisconnect(object? sender, NetChannelArgs args)
{
if (!_notify || !IsPendingRageQuit(args.Channel.UserId))
return;

var callout = GetCallout(args.Channel);
_chat.ChatMessageToAll(ChatChannel.OOC, callout, callout, _ent, false, true, colorOverride: Color.FromHex("#fff0ff", Color.Honeydew));
}

private void OnActorMobStateChanged(Entity<ActorComponent> ent, ref MobStateChangedEvent args)
{
if (args.OldMobState == MobState.Invalid || args.NewMobState < args.OldMobState)
return;

var target = ent.Comp.PlayerSession;
StartTimer(target);
}

private void StartTimer(ICommonSession target)
{
AddTimer(target);
Timer.Spawn(TimeSpan.FromSeconds(_timer), () => ClearTimer(target));
}

private string GetCallout(INetChannel chan)
{
return Loc.GetString("rage-quit-notify", ("player", chan.UserName));
}

private void AddTimer(ICommonSession target)
{
GetPendingRageQuitList().Add(target.UserId);
}

private void ClearTimer(ICommonSession target)
{
GetPendingRageQuitList().Remove(target.UserId);
}

private bool IsPendingRageQuit(NetUserId target)
{
return GetPendingRageQuitList().Contains(target);
}

private HashSet<NetUserId> GetPendingRageQuitList()
{
// This has to be a trycomp due to tests not actually creating the entity anyway
TryComp<PlayerListenerComponent>(_ent, out var plcomp);

return plcomp?.UserIds ?? [];
}
}
15 changes: 14 additions & 1 deletion Content.Shared/_Goobstation/CCVars/CCVars.Goob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ public sealed partial class GoobCVars
public static readonly CVarDef<bool> SiloEnabled =
CVarDef.Create("goob.silo_enabled", true, CVar.SERVER | CVar.REPLICATED);

/// <summary>
/// Broadcast to all players that a player has ragequit.
/// </summary>
public static readonly CVarDef<bool> PlayerRageQuitNotify =
CVarDef.Create("player.ragequit.notify", true, CVar.SERVERONLY);

/// <summary>
/// Time between being eligible for a "rage quit" after reaching a damage threshold.
/// Default is 5f.
/// </summary>
public static readonly CVarDef<float> PlayerRageQuitTimeThreshold =
CVarDef.Create("player.ragequit.threshold", 5f);

#region Surgery

public static readonly CVarDef<bool> CanOperateOnSelf =
Expand Down Expand Up @@ -149,7 +162,7 @@ public sealed partial class GoobCVars

public static readonly CVarDef<bool> BlobCanGrowInSpace =
CVarDef.Create("blob.grow_space", true, CVar.SERVER);

#endregion

#region Mechs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rage-quit-notify = {$player} has rage quit the server.

0 comments on commit 11cec21

Please sign in to comment.