From a649749ea0a122cbe6a33fa30eb014cb1d33a760 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Thu, 27 Nov 2025 22:04:42 -0700 Subject: [PATCH] [MIRROR] Ports "Fixes SS_KEEP_TIMING causing RUNLEVEL_LOBBY subsystems to fire with 75% their set wait" from /TG/ (#12053) Co-authored-by: Cameron Lennox --- code/__defines/_lists.dm | 2 +- code/_helpers/_lists.dm | 16 ++++---- code/_helpers/sorts/__main.dm | 2 +- code/controllers/master.dm | 37 +++++++++++++++---- .../ControllerOverview/constants.ts | 4 +- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/code/__defines/_lists.dm b/code/__defines/_lists.dm index 2533653138..7483cc726a 100644 --- a/code/__defines/_lists.dm +++ b/code/__defines/_lists.dm @@ -42,7 +42,7 @@ // Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression. #define SANITIZE_LIST(L) ( islist(L) ? L : list() ) -#define reverseList(L) reverseRange(L.Copy()) +#define reverseList(L) reverse_range(L.Copy()) #define islist(L) istype(L, /list) diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm index 2cfb2d37fe..ae2e6d506e 100644 --- a/code/_helpers/_lists.dm +++ b/code/_helpers/_lists.dm @@ -849,20 +849,20 @@ Checks if a list has the same entries and values as an element of big. L.Cut(fromIndex, fromIndex+1) //replaces reverseList ~Carnie -/proc/reverseRange(list/L, start=1, end=0) - if(L.len) - start = start % L.len - end = end % (L.len+1) +/proc/reverse_range(list/inserted_list, start = 1, end = 0) + if(inserted_list.len) + start = start % inserted_list.len + end = end % (inserted_list.len + 1) if(start <= 0) - start += L.len + start += inserted_list.len if(end <= 0) - end += L.len + 1 + end += inserted_list.len + 1 --end while(start < end) - L.Swap(start++,end--) + inserted_list.Swap(start++, end--) - return L + return inserted_list //Copies a list, and all lists inside it recusively //Does not copy any other reference type diff --git a/code/_helpers/sorts/__main.dm b/code/_helpers/sorts/__main.dm index c5cd572769..a8c87806ea 100644 --- a/code/_helpers/sorts/__main.dm +++ b/code/_helpers/sorts/__main.dm @@ -173,7 +173,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new()) if(call(cmp)(current, last) >= 0) break ++runHi - reverseRange(L, lo, runHi) + reverse_range(L, lo, runHi) else while(runHi < hi) last = current diff --git a/code/controllers/master.dm b/code/controllers/master.dm index aee5a58ed3..33f858da02 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -137,7 +137,7 @@ GLOBAL_REAL(Master, /datum/controller/master) /datum/controller/master/Shutdown() processing = FALSE sortTim(subsystems, GLOBAL_PROC_REF(cmp_subsystem_init)) - reverseRange(subsystems) + reverse_range(subsystems) for(var/datum/controller/subsystem/ss in subsystems) log_world("Shutting down [ss.name] subsystem...") if (ss.slept_count > 0) @@ -195,7 +195,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie "cost_ms" = subsystem.cost, "tick_usage" = subsystem.tick_usage, "usage_per_tick" = average, - "tick_overrun" = subsystem.tick_overrun, + "overtime" = subsystem.tick_overrun, "initialized" = subsystem.initialized, "initialization_failure_message" = subsystem.initialization_failure_message, )) @@ -224,6 +224,12 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie return TRUE if("view_variables") + if(!check_rights_for(ui.user.client, R_DEBUG)) + message_admins( + "[key_name(ui.user)] tried to view master controller variables while having improper rights, \ + this is potentially a malicious exploit and worth noting." + ) + var/datum/controller/subsystem/subsystem = locate(params["ref"]) in subsystems if(isnull(subsystem)) to_chat(ui.user, span_warning("Failed to locate subsystem.")) @@ -339,7 +345,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie // Allows subsystems to declare other subsystems that must initialize after them. for(var/datum/controller/subsystem/subsystem as anything in subsystems) - for(var/dependent_type as anything in subsystem.dependents) + for(var/dependent_type in subsystem.dependents) if(!ispath(dependent_type, /datum/controller/subsystem)) stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an invalid dependent: `[dependent_type]`. Skipping") continue @@ -349,7 +355,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie // Constructs a reverse-dependency graph. for(var/datum/controller/subsystem/subsystem as anything in subsystems) - for(var/dependency_type as anything in subsystem.dependencies) + for(var/dependency_type in subsystem.dependencies) if(!ispath(dependency_type, /datum/controller/subsystem)) stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an invalid dependency: `[dependency_type]`. Skipping") continue @@ -383,11 +389,11 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie // Topological sorting algorithm end if(length(subsystems) != length(sorted_subsystems)) - var/list/circular_dependency = subsystems.Copy() - sorted_subsystems + var/list/circular_dependency = subsystems - sorted_subsystems var/list/debug_msg = list() var/list/usr_msg = list() for(var/datum/controller/subsystem/subsystem as anything in circular_dependency) - usr_msg += "[subsystem.name]" + usr_msg += subsystem.name var/list/datum/controller/subsystem/nodes = list(circular_dependency[1]) var/list/loop = list() @@ -604,10 +610,19 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie if ((SS.flags & (SS_TICKER|SS_BACKGROUND)) == SS_TICKER) tickersubsystems += SS // Timer subsystems aren't allowed to bunch up, so we offset them a bit - timer += world.tick_lag * rand(0, 1) + timer += TICKS2DS(rand(0, 1)) SS.next_fire = timer continue + // Now, we have to set starting next_fires for all our new non ticker kids + if(SS.init_stage == init_stage - 1 && (SS.runlevels & current_runlevel)) + // Give em a random offset so things don't clump up too bad + var/delay = SS.wait + if(SS.flags & SS_TICKER) + delay = TICKS2DS(delay) + // Gotta convert to ticks cause rand needs integers + SS.next_fire = world.time + TICKS2DS(rand(0, DS2TICKS(min(delay, 2 SECONDS)))) + var/ss_runlevels = SS.runlevels var/added_to_any = FALSE for(var/I in 1 to GLOB.bitflags.len) @@ -703,7 +718,11 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie //we only want to offset it if it's new and also behind if(SS.next_fire > world.time || (SS in old_subsystems)) continue - SS.next_fire = world.time + world.tick_lag * rand(0, DS2TICKS(min(SS.wait, 2 SECONDS))) + // If they're new, give em a random offset so things don't clump up too bad + var/delay = SS.wait + if(SS.flags & SS_TICKER) + delay = TICKS2DS(delay) + SS.next_fire = world.time + TICKS2DS(rand(0, DS2TICKS(min(delay, 2 SECONDS)))) subsystems_to_check = current_runlevel_subsystems else @@ -798,6 +817,8 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie if (SS_flags & SS_NO_FIRE) subsystemstocheck -= SS continue + // If we're keeping timing and running behind, + // fire at most 25% faster then normal to try and make up the gap without spamming if ((SS_flags & (SS_TICKER|SS_KEEP_TIMING)) == SS_KEEP_TIMING && SS.last_fire + (SS.wait * 0.75) > world.time) continue if (SS.postponed_fires >= 1) diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/constants.ts b/tgui/packages/tgui/interfaces/ControllerOverview/constants.ts index 62953cc7dd..accad50341 100644 --- a/tgui/packages/tgui/interfaces/ControllerOverview/constants.ts +++ b/tgui/packages/tgui/interfaces/ControllerOverview/constants.ts @@ -41,8 +41,8 @@ export const SORTING_TYPES: readonly SortType[] = [ inDeciseconds: true, }, { - label: 'Tick Overrun', - propName: 'tick_overrun', + label: 'Subsystem Overtime', + propName: 'overtime', inDeciseconds: true, }, ];