From 6fc487531cabba44c361873e8d3faa04619f603d Mon Sep 17 00:00:00 2001
From: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Date: Fri, 12 Dec 2025 01:58:51 +0100
Subject: [PATCH] Add small cooldown to NukeKeypadEnterMessages (#41831)
* cooldown
* d
* time offset serializer
* undo button disabling according to feedback
* Update Content.Client/Nuke/NukeBoundUserInterface.cs
---
Content.Server/Nuke/NukeComponent.cs | 9 +++++++++
Content.Server/Nuke/NukeSystem.cs | 10 ++++++++--
Content.Shared/Nuke/NukeUiMessages.cs | 6 ++++++
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/Content.Server/Nuke/NukeComponent.cs b/Content.Server/Nuke/NukeComponent.cs
index cd1c0227eb..e46680460f 100644
--- a/Content.Server/Nuke/NukeComponent.cs
+++ b/Content.Server/Nuke/NukeComponent.cs
@@ -5,6 +5,7 @@ using Content.Shared.Explosion;
using Content.Shared.Nuke;
using Robust.Shared.Audio;
using Robust.Shared.Map;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Nuke
@@ -164,6 +165,14 @@ namespace Content.Server.Nuke
[DataField]
public string EnteredCode = "";
+ ///
+ /// Time at which the last nuke code was entered.
+ /// Used to apply a cooldown to prevent clients from attempting to brute force the nuke code by sending keypad messages every tick.
+ ///
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan LastCodeEnteredAt = TimeSpan.Zero;
+
///
/// Current status of a nuclear bomb.
///
diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs
index 3788d2b2ab..130cc19656 100644
--- a/Content.Server/Nuke/NukeSystem.cs
+++ b/Content.Server/Nuke/NukeSystem.cs
@@ -18,11 +18,10 @@ using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
-using Robust.Shared.Map;
using Robust.Shared.Map.Components;
-using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Utility;
+using Robust.Shared.Timing;
namespace Content.Server.Nuke;
@@ -45,6 +44,7 @@ public sealed class NukeSystem : EntitySystem
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
///
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
@@ -232,6 +232,12 @@ public sealed class NukeSystem : EntitySystem
if (component.Status != NukeStatus.AWAIT_CODE)
return;
+ var curTime = _timing.CurTime;
+ if (curTime < component.LastCodeEnteredAt + SharedNukeComponent.EnterCodeCooldown)
+ return; // Validate that they are not entering codes faster than the cooldown.
+
+ component.LastCodeEnteredAt = curTime;
+
UpdateStatus(uid, component);
UpdateUserInterface(uid, component);
}
diff --git a/Content.Shared/Nuke/NukeUiMessages.cs b/Content.Shared/Nuke/NukeUiMessages.cs
index 1c35cac7b0..8f5e16395c 100644
--- a/Content.Shared/Nuke/NukeUiMessages.cs
+++ b/Content.Shared/Nuke/NukeUiMessages.cs
@@ -5,6 +5,12 @@ namespace Content.Shared.Nuke
public abstract partial class SharedNukeComponent : Component
{
public const string NukeDiskSlotId = "Nuke";
+
+ ///
+ /// Cooldown time between attempts to enter the nuke code.
+ /// Used to prevent clients from trying to brute force it.
+ ///
+ public static readonly TimeSpan EnterCodeCooldown = TimeSpan.FromSeconds(1);
}
[Serializable, NetSerializable]
--
2.52.0