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
[DataField]
public string EnteredCode = "";
+ /// <summary>
+ /// 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.
+ /// <seealso cref="SharedNukeComponent.EnterCodeCooldown"/>
+ /// </summary>
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan LastCodeEnteredAt = TimeSpan.Zero;
+
/// <summary>
/// Current status of a nuclear bomb.
/// </summary>
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;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
/// <summary>
/// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx
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);
}
public abstract partial class SharedNukeComponent : Component
{
public const string NukeDiskSlotId = "Nuke";
+
+ /// <summary>
+ /// Cooldown time between attempts to enter the nuke code.
+ /// Used to prevent clients from trying to brute force it.
+ /// </summary>
+ public static readonly TimeSpan EnterCodeCooldown = TimeSpan.FromSeconds(1);
}
[Serializable, NetSerializable]