From a6d9b47a7dbbba04240e76350a8c6cc646309bb8 Mon Sep 17 00:00:00 2001
From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Date: Sat, 21 Oct 2023 15:18:59 -0400
Subject: [PATCH] Updates signaler investigate code | Adds some nice QOL
changes for signalers | Enforces cooldown on signaler circuitry (#78974)
See title.
If someone was abusing signalers previously to cause server lag, going
into list signalers would actually cause even worse lag as byond sat
there and processed thousands of items into a string over and over,
which would cause string format operations on longer and longer strings,
resulting in more and more overhead. This is bad.
So instead there is now a limit to the size of the list, currently I
have that set to 500 although I am open to increasing and even reducing
the number.
I have also made signalers slightly more intuitive by having the
cooldown actually displayed in the ui as a tooltip instead of just being
a secret feature you didnt know about unless you code dived. Also made
the cooldown actually respected by things such as circuitry where it
didnt even implement the cooldown and would happily send as many signals
as you had items connected to your proximity circuit.
Admins won't accidentally kill the server by trying to parse a lag
machines signal list. Players lagging the server? No, how about the
admins trying to fix it!
:cl:
qol: signalers now tell you their cooldown and also use balloon alerts
/:cl:
---
code/__DEFINES/logging.dm | 3 ++
code/_globalvars/logging.dm | 14 +++++++--
code/modules/admin/verbs/list_exposer.dm | 4 +--
code/modules/assembly/signaler.dm | 30 +++++++++++--------
.../file_system/programs/signalcommander.dm | 19 ++++++++----
.../wiremod/components/action/radio.dm | 16 ++++++++--
tgui/packages/tgui/interfaces/Signaler.jsx | 3 +-
7 files changed, 64 insertions(+), 25 deletions(-)
diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm
index 8caf205817f6..62c770e6322e 100644
--- a/code/__DEFINES/logging.dm
+++ b/code/__DEFINES/logging.dm
@@ -5,6 +5,9 @@
/// Admins can still manually request a re-render
#define LOG_UPDATE_TIMEOUT 5 SECONDS
+// The maximum number of entries allowed in the signaler investigate log, keep this relatively small to prevent performance issues when an admin tries to query it
+#define INVESTIGATE_SIGNALER_LOG_MAX_LENGTH 500
+
//Investigate logging defines
#define INVESTIGATE_ACCESSCHANGES "id_card_changes"
#define INVESTIGATE_ATMOS "atmos"
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index 914665d17987..8a57ad13ea7e 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -61,9 +61,17 @@ GLOBAL_PROTECT(admin_activities)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
-/// All signals here in format: "[src] used [REF(src)] @ location [src.loc]: [freq]/[code]"
-GLOBAL_LIST_EMPTY(lastsignalers)
-GLOBAL_PROTECT(lastsignalers)
+/// Investigate log for signaler usage, use the add_to_signaler_investigate_log proc
+GLOBAL_LIST_EMPTY(investigate_signaler)
+GLOBAL_PROTECT(investigate_signaler)
+
+/// Used to add a text log to the signaler investigation log.
+/// Do not add to the list directly; if the list is too large it can cause lag when an admin tries to view it.
+/proc/add_to_signaler_investigate_log(text)
+ var/log_length = length(GLOB.investigate_signaler)
+ if(log_length >= INVESTIGATE_SIGNALER_LOG_MAX_LENGTH)
+ GLOB.investigate_signaler = GLOB.investigate_signaler.Copy((INVESTIGATE_SIGNALER_LOG_MAX_LENGTH - log_length) + 2)
+ GLOB.investigate_signaler += list(text)
/// Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_LIST_EMPTY(lawchanges)
diff --git a/code/modules/admin/verbs/list_exposer.dm b/code/modules/admin/verbs/list_exposer.dm
index c2c48963051e..00a5960b3658 100644
--- a/code/modules/admin/verbs/list_exposer.dm
+++ b/code/modules/admin/verbs/list_exposer.dm
@@ -13,8 +13,8 @@
if(!SSticker.HasRoundStarted())
tgui_alert(usr, "The game hasn't started yet!")
return
- var/data = "Showing last [length(GLOB.lastsignalers)] signalers.
"
- for(var/entry in GLOB.lastsignalers)
+ var/data = "Showing last [length(GLOB.investigate_signaler)] signalers."
+ for(var/entry in GLOB.investigate_signaler)
data += "[entry] "
usr << browse(data, "window=lastsignalers;size=800x500")
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index de9a27404972..d38d20790e14 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -10,15 +10,20 @@
drop_sound = 'sound/items/handling/component_drop.ogg'
pickup_sound = 'sound/items/handling/component_pickup.ogg'
+ /// The code sent by this signaler.
var/code = DEFAULT_SIGNALER_CODE
+ /// The frequency this signaler is set to.
var/frequency = FREQ_SIGNALER
+ /// How long of a cooldown exists on this signaller.
+ var/cooldown_length = 1 SECONDS
+ /// The radio frequency connection this signaler is using.
var/datum/radio_frequency/radio_connection
- ///Holds the mind that commited suicide.
+ /// Holds the mind that commited suicide.
var/datum/mind/suicider
- ///Holds a reference string to the mob, decides how much of a gamer you are.
+ /// Holds a reference string to the mob, decides how much of a gamer you are.
var/suicide_mob
+ /// How many tiles away can you hear when this signaler is used or gets activated.
var/hearing_range = 1
-
/// String containing the last piece of logging data relating to when this signaller has received a signal.
var/last_receive_signal_log
@@ -77,23 +82,26 @@
/obj/item/assembly/signaler/ui_data(mob/user)
var/list/data = list()
data["frequency"] = frequency
+ data["cooldown"] = cooldown_length
data["code"] = code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
return data
-/obj/item/assembly/signaler/ui_act(action, params)
+/obj/item/assembly/signaler/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("signal")
- if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND))
- to_chat(usr, span_warning("[src] is still recharging..."))
- return
- TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, 1 SECONDS)
+ if(cooldown_length > 0)
+ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND))
+ balloon_alert(ui.user, "recharging!")
+ return
+ TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, cooldown_length)
INVOKE_ASYNC(src, PROC_REF(signal))
+ balloon_alert(ui.user, "signaled")
. = TRUE
if("freq")
var/new_frequency = sanitize_frequency(unformat_frequency(params["freq"]), TRUE)
@@ -141,10 +149,8 @@
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(src)
- var/logging_data
- if(usr)
- logging_data = "[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]"
- GLOB.lastsignalers.Add(logging_data)
+ var/logging_data = "[time] : [key_name(usr)] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]"
+ add_to_signaler_investigate_log(logging_data)
var/datum/signal/signal = new(list("code" = code), logging_data = logging_data)
radio_connection.post_signal(src, signal)
diff --git a/code/modules/modular_computers/file_system/programs/signalcommander.dm b/code/modules/modular_computers/file_system/programs/signalcommander.dm
index 6d636bab370a..e8140b62b17c 100644
--- a/code/modules/modular_computers/file_system/programs/signalcommander.dm
+++ b/code/modules/modular_computers/file_system/programs/signalcommander.dm
@@ -14,6 +14,10 @@
var/signal_code = DEFAULT_SIGNALER_CODE
/// Radio connection datum used by signalers.
var/datum/radio_frequency/radio_connection
+ /// How long do we cooldown before we can send another signal?
+ var/signal_cooldown_time = 1 SECONDS
+ /// Cooldown store
+ COOLDOWN_DECLARE(signal_cooldown)
/datum/computer_file/program/signal_commander/on_start(mob/living/user)
. = ..()
@@ -26,6 +30,7 @@
/datum/computer_file/program/signal_commander/ui_data(mob/user)
var/list/data = list()
data["frequency"] = signal_frequency
+ data["cooldown"] = signal_cooldown_time
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
@@ -55,13 +60,18 @@
if(!radio_connection)
return
+ if(!COOLDOWN_FINISHED(src, signal_cooldown))
+ computer.balloon_alert(usr, "cooling down!")
+ return
+
+ COOLDOWN_START(src, signal_cooldown, signal_cooldown_time)
+ computer.balloon_alert(usr, "signaled")
+
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(computer)
- var/logging_data
- if(usr)
- logging_data = "[time] : [usr.key] used [computer] @ location ([T.x],[T.y],[T.z]) : [format_frequency(signal_frequency)]/[signal_code]"
- GLOB.lastsignalers.Add(logging_data)
+ var/logging_data = "[time] : [key_name(usr)] used the computer '[initial(computer.name)]' @ location ([T.x],[T.y],[T.z]) : [format_frequency(signal_frequency)]/[signal_code]"
+ add_to_signaler_investigate_log(logging_data)
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
radio_connection.post_signal(computer, signal)
@@ -70,4 +80,3 @@
SSradio.remove_object(computer, signal_frequency)
signal_frequency = new_frequency
radio_connection = SSradio.add_object(computer, signal_frequency, RADIO_SIGNALER)
- return
diff --git a/code/modules/wiremod/components/action/radio.dm b/code/modules/wiremod/components/action/radio.dm
index cd13e0e1e451..74b2c54c1b81 100644
--- a/code/modules/wiremod/components/action/radio.dm
+++ b/code/modules/wiremod/components/action/radio.dm
@@ -28,8 +28,17 @@
/// The ckey of the user who used the shell we were placed in, important for signalling logs.
var/owner_ckey = null
+ /// The radio connection we are using to receive signals.
var/datum/radio_frequency/radio_connection
+ /// How long of a cooldown we have before we can send another signal.
+ var/signal_cooldown_time = 1 SECONDS
+
+/obj/item/circuit_component/radio/Initialize(mapload)
+ . = ..()
+ if(signal_cooldown_time > 0)
+ desc = "[desc] It has a [signal_cooldown_time * 0.1] second cooldown between sending signals."
+
/obj/item/circuit_component/radio/register_shell(atom/movable/shell)
parent_shell = shell
var/potential_fingerprints = shell.fingerprintslast
@@ -65,8 +74,10 @@
INVOKE_ASYNC(src, PROC_REF(handle_radio_input), port)
/obj/item/circuit_component/radio/proc/handle_radio_input(datum/port/input/port)
- var/frequency = freq.value
+ if(!TIMER_COOLDOWN_CHECK(parent, COOLDOWN_SIGNALLER_SEND))
+ return
+ var/frequency = freq.value
if(frequency != current_freq)
SSradio.remove_object(src, current_freq)
radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER)
@@ -84,7 +95,8 @@
loggable_strings += ": The last fingerprints on the containing shell was [parent_shell.fingerprintslast]."
var/loggable_string = loggable_strings.Join(" ")
- GLOB.lastsignalers.Add(loggable_string)
+ add_to_signaler_investigate_log(loggable_string)
+ TIMER_COOLDOWN_START(parent, COOLDOWN_SIGNALLER_SEND, signal_cooldown_time)
var/datum/signal/signal = new(list("code" = signal_code, "key" = parent?.owner_id), logging_data = loggable_string)
radio_connection.post_signal(src, signal)
diff --git a/tgui/packages/tgui/interfaces/Signaler.jsx b/tgui/packages/tgui/interfaces/Signaler.jsx
index 81ee5a370c81..f3348b081c6c 100644
--- a/tgui/packages/tgui/interfaces/Signaler.jsx
+++ b/tgui/packages/tgui/interfaces/Signaler.jsx
@@ -16,7 +16,7 @@ export const Signaler = (props) => {
export const SignalerContent = (props) => {
const { act, data } = useBackend();
- const { code, frequency, minFrequency, maxFrequency } = data;
+ const { code, frequency, cooldown, minFrequency, maxFrequency } = data;
const color = 'rgba(13, 13, 213, 0.7)';
const backColor = 'rgba(0, 0, 69, 0.5)';
return (
@@ -94,6 +94,7 @@ export const SignalerContent = (props) => {