From b996d5c6b2a34f9a1f3de2f88bfc347f0cdb1da5 Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 7 Jun 2017 13:55:34 -0400 Subject: [PATCH 1/5] Ports utility macros to let subsystems divide their time among a few tasks Port of https://github.com/tgstation/tgstation/pull/26324 --- code/__defines/MC.dm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm index 08b8d223ec..59fb0d4db7 100644 --- a/code/__defines/MC.dm +++ b/code/__defines/MC.dm @@ -1,4 +1,15 @@ #define MC_TICK_CHECK ( ( world.tick_usage > CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 ) + +// Used for splitting up your remaining time into phases, if you want to evenly divide it. +#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count +#define MC_SPLIT_TICK \ + if(split_tick_phases > 1){\ + CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\ + --split_tick_phases;\ + } else {\ + CURRENT_TICKLIMIT = original_tick_limit;\ + } + // Used to smooth out costs to try and avoid oscillation. #define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current)) #define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current)) From 82e90a206c1e24147b7073e948fc63c4f232ecdc Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 7 Jun 2017 16:42:06 -0400 Subject: [PATCH 2/5] Ports "Better repeated MC crash handling" * From https://github.com/tgstation/tgstation/pull/25813 * If the MC crashes: The problem subsystem will be rebooted on its 2nd strike and disabled on its third. --- code/controllers/master.dm | 19 +++++++++++++++++++ code/controllers/subsystem.dm | 2 ++ 2 files changed, 21 insertions(+) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 360b739bad..fbf97f730c 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -107,7 +107,26 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING else msg += "\t [varname] = [varval]\n" log_world(msg) + + var/datum/controller/subsystem/BadBoy = Master.last_type_processed + var/FireHim = FALSE + if(istype(BadBoy)) + msg = null + switch(++BadBoy.failure_strikes) + if(2) + msg = "The [BadBoy.name] subsystem was the last to fire for 2 controller restarts. It will be recovered now and disabled if it happens again." + FireHim = TRUE + if(3) + msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined." + BadBoy.flags |= SS_NO_FIRE + if(msg) + log_game(msg) + message_admins("[msg]") + log_world(msg) + if (istype(Master.subsystems)) + if(FireHim) + Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one subsystems = Master.subsystems StartProcessing(10) else diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index ff81fdc23e..b3e27a0175 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -27,6 +27,8 @@ var/datum/controller/subsystem/queue_next var/datum/controller/subsystem/queue_prev + var/static/failure_strikes = 0 //How many times we suspect this subsystem has crashed the MC, 3 strikes and you're out! + //Do not override /datum/controller/subsystem/New() return From 6a8abd4f80ae8d9b0c244dd85505fa542a33cf35 Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 7 Jun 2017 17:50:07 -0400 Subject: [PATCH 3/5] Ports tg improvements in StonedMC subsystem * Ports /tg StonedMC Enhancement - Runlevels - Lets services more precicely define when they want to fire - in the lobby, during game, only after, etc. Includes bugfixes from: * https://github.com/tgstation/tgstation/pull/27132 * https://github.com/tgstation/tgstation/pull/27338 * https://github.com/tgstation/tgstation/pull/27576 * https://github.com/tgstation/tgstation/pull/27519 * Ports Standardizes subsystem Shutdown order - https://github.com/tgstation/tgstation/pull/26228 --- code/__defines/MC.dm | 19 +++--- code/__defines/subsystems.dm | 13 ++++ code/controllers/master.dm | 94 +++++++++++++++----------- code/controllers/subsystem.dm | 1 + code/controllers/subsystems/garbage.dm | 3 +- polaris.dme | 1 + 6 files changed, 79 insertions(+), 52 deletions(-) create mode 100644 code/__defines/subsystems.dm diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm index 59fb0d4db7..297f04c148 100644 --- a/code/__defines/MC.dm +++ b/code/__defines/MC.dm @@ -21,39 +21,36 @@ //SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) -//subsystem should fire during pre-game lobby. -#define SS_FIRE_IN_LOBBY 1 - //subsystem does not initialize. -#define SS_NO_INIT 2 +#define SS_NO_INIT 1 //subsystem does not fire. // (like can_fire = 0, but keeps it from getting added to the processing subsystems list) // (Requires a MC restart to change) -#define SS_NO_FIRE 4 +#define SS_NO_FIRE 2 //subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) // SS_BACKGROUND has its own priority bracket -#define SS_BACKGROUND 8 +#define SS_BACKGROUND 4 //subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background)) -#define SS_NO_TICK_CHECK 16 +#define SS_NO_TICK_CHECK 8 //Treat wait as a tick count, not DS, run every wait ticks. // (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems) -// (implies SS_FIRE_IN_LOBBY because of how it works) +// (implies all runlevels because of how it works) // (overrides SS_BACKGROUND) // This is designed for basically anything that works as a mini-mc (like SStimer) -#define SS_TICKER 32 +#define SS_TICKER 16 //keep the subsystem's timing on point by firing early if it fired late last fire because of lag // ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds. -#define SS_KEEP_TIMING 64 +#define SS_KEEP_TIMING 32 //Calculate its next fire after its fired. // (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be) // This flag overrides SS_KEEP_TIMING -#define SS_POST_FIRE_TIMING 128 +#define SS_POST_FIRE_TIMING 64 //SUBSYSTEM STATES #define SS_IDLE 0 //aint doing shit. diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm new file mode 100644 index 0000000000..8c546c9135 --- /dev/null +++ b/code/__defines/subsystems.dm @@ -0,0 +1,13 @@ + +// SS runlevels + +#define RUNLEVEL_INIT 0 // "Initialize Only" - Used for subsystems that should never be fired (Should also have SS_NO_FIRE set) +#define RUNLEVEL_LOBBY 1 // Initial runlevel before setup. Returns to here if setup fails. +#define RUNLEVEL_SETUP 2 // While the gamemode setup is running. I.E gameticker.setup() +#define RUNLEVEL_GAME 4 // After successful game ticker setup, while the round is running. +#define RUNLEVEL_POSTGAME 8 // When round completes but before reboot + +#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) + +var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) +#define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list diff --git a/code/controllers/master.dm b/code/controllers/master.dm index fbf97f730c..6bcfb6ff0a 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -40,8 +40,6 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING var/make_runtime = 0 var/initializations_finished_with_no_players_logged_in //I wonder what this could be? - // Has round started? (So we know what subsystems to run) - var/round_started = 0 // The type of the last subsystem to be process()'d. var/last_type_processed @@ -52,6 +50,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING var/queue_priority_count_bg = 0 //Same, but for background subsystems var/map_loading = FALSE //Are we loading in a new map? + var/current_runlevel //for scheduling different subsystems for different stages of the round + /datum/controller/master/New() // Highlander-style: there can only be one! Kill off the old and replace it with the new. subsystems = list() @@ -70,6 +70,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING /datum/controller/master/Shutdown() processing = FALSE + sortTim(subsystems, /proc/cmp_subsystem_init) + reverseRange(subsystems) for(var/datum/controller/subsystem/ss in subsystems) ss.Shutdown() @@ -128,6 +130,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING if(FireHim) Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one subsystems = Master.subsystems + current_runlevel = Master.current_runlevel StartProcessing(10) else to_chat(world, "The Master Controller is having some issues, we will need to re-initialize EVERYTHING") @@ -165,6 +168,9 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING to_chat(world, "[msg]") log_world(msg) + if (!current_runlevel) + SetRunLevel(RUNLEVEL_LOBBY) + // Sort subsystems by display setting for easy access. sortTim(subsystems, /proc/cmp_subsystem_display) // Set world options. @@ -180,16 +186,12 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING // Loop. Master.StartProcessing(0) -// Notify the MC that the round has started. -/datum/controller/master/proc/RoundStart() - round_started = 1 - var/timer = world.time - for (var/datum/controller/subsystem/SS in subsystems) - if (SS.flags & SS_FIRE_IN_LOBBY || SS.flags & SS_TICKER) - continue //already firing - // Stagger subsystems. - timer += world.tick_lag * rand(1, 5) - SS.next_fire = timer +/datum/controller/master/proc/SetRunLevel(new_runlevel) + var/old_runlevel = isnull(current_runlevel) ? "NULL" : runlevel_flags[current_runlevel] + testing("MC: Runlevel changed from [old_runlevel] to [new_runlevel]") + current_runlevel = RUNLEVEL_FLAG_TO_INDEX(new_runlevel) + if(current_runlevel < 1) + CRASH("Attempted to set invalid runlevel: [new_runlevel]") // Starts the mc, and sticks around to restart it if the loop ever ends. /datum/controller/master/proc/StartProcessing(delay) @@ -214,12 +216,9 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING //Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because // local vars rock - // Schedule the first run of the Subsystems. - round_started = world.has_round_started() //all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed) var/list/tickersubsystems = list() - var/list/normalsubsystems = list() - var/list/lobbysubsystems = list() + var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel var/timer = world.time for (var/thing in subsystems) var/datum/controller/subsystem/SS = thing @@ -234,25 +233,29 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING timer += world.tick_lag * rand(1, 5) SS.next_fire = timer continue - if (SS.flags & SS_FIRE_IN_LOBBY) - lobbysubsystems += SS - timer += world.tick_lag * rand(1, 5) - SS.next_fire = timer - else if (round_started) - timer += world.tick_lag * rand(1, 5) - SS.next_fire = timer - normalsubsystems += SS + + var/ss_runlevels = SS.runlevels + var/added_to_any = FALSE + for(var/I in 1 to global.runlevel_flags.len) + if(ss_runlevels & global.runlevel_flags[I]) + while(runlevel_sorted_subsystems.len < I) + runlevel_sorted_subsystems += list(list()) + runlevel_sorted_subsystems[I] += SS + added_to_any = TRUE + if(!added_to_any) + WARNING("[SS.name] subsystem is not SS_NO_FIRE but also does not have any runlevels set!") queue_head = null queue_tail = null //these sort by lower priorities first to reduce the number of loops needed to add subsequent SS's to the queue //(higher subsystems will be sooner in the queue, adding them later in the loop means we don't have to loop thru them next queue add) sortTim(tickersubsystems, /proc/cmp_subsystem_priority) - sortTim(normalsubsystems, /proc/cmp_subsystem_priority) - sortTim(lobbysubsystems, /proc/cmp_subsystem_priority) + for(var/I in runlevel_sorted_subsystems) + sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority) + I += tickersubsystems - normalsubsystems += tickersubsystems - lobbysubsystems += tickersubsystems + var/cached_runlevel = current_runlevel + var/list/current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] init_timeofday = REALTIMEOFDAY init_time = world.time @@ -289,14 +292,23 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time)) new/datum/controller/failsafe() // (re)Start the failsafe. if (!queue_head || !(iteration % 3)) - if (round_started) - subsystems_to_check = normalsubsystems - else - subsystems_to_check = lobbysubsystems + var/checking_runlevel = current_runlevel + if(cached_runlevel != checking_runlevel) + //resechedule subsystems + cached_runlevel = checking_runlevel + current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel] + var/stagger = world.time + for(var/I in current_runlevel_subsystems) + var/datum/controller/subsystem/SS = I + if(SS.next_fire <= world.time) + stagger += world.tick_lag * rand(1, 5) + SS.next_fire = stagger + + subsystems_to_check = current_runlevel_subsystems else subsystems_to_check = tickersubsystems if (CheckQueue(subsystems_to_check) <= 0) - if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems)) + if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems)) log_world("MC: SoftReset() failed, crashing") return if (!error_level) @@ -308,7 +320,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING if (queue_head) if (RunQueue() <= 0) - if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems)) + if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems)) log_world("MC: SoftReset() failed, crashing") return if (!error_level) @@ -479,13 +491,15 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING //resets the queue, and all subsystems, while filtering out the subsystem lists // called if any mc's queue procs runtime or exit improperly. -/datum/controller/master/proc/SoftReset(list/ticker_SS, list/normal_SS, list/lobby_SS) +/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS) . = 0 log_world("MC: SoftReset called, resetting MC queue state.") - if (!istype(subsystems) || !istype(ticker_SS) || !istype(normal_SS) || !istype(lobby_SS)) - log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[normal_SS]' '[lobby_SS]' Crashing!") + if (!istype(subsystems) || !istype(ticker_SS) || !istype(runlevel_SS)) + log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'") return - var/subsystemstocheck = subsystems + ticker_SS + normal_SS + lobby_SS + var/subsystemstocheck = subsystems + ticker_SS + for(var/I in runlevel_SS) + subsystemstocheck |= I for (var/thing in subsystemstocheck) var/datum/controller/subsystem/SS = thing @@ -493,8 +507,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING //list(SS) is so if a list makes it in the subsystem list, we remove the list, not the contents subsystems -= list(SS) ticker_SS -= list(SS) - normal_SS -= list(SS) - lobby_SS -= list(SS) + for(var/I in runlevel_SS) + I -= list(SS) log_world("MC: SoftReset: Found bad entry in subsystem list, '[SS]'") continue if (SS.queue_next && !istype(SS.queue_next)) diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index b3e27a0175..7dff609c76 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -6,6 +6,7 @@ var/priority = 50 //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again) + var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire //set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later // use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index b07337e803..d6db860d5d 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -5,7 +5,8 @@ SUBSYSTEM_DEF(garbage) name = "Garbage" priority = 15 wait = 5 - flags = SS_FIRE_IN_LOBBY|SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT + flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY var/collection_timeout = 3000// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object var/delslasttick = 0 // number of del()'s we've done this tick diff --git a/polaris.dme b/polaris.dme index 3b49b9566b..83159a4621 100644 --- a/polaris.dme +++ b/polaris.dme @@ -40,6 +40,7 @@ #include "code\__defines\qdel.dm" #include "code\__defines\research.dm" #include "code\__defines\species_languages.dm" +#include "code\__defines\subsystems.dm" #include "code\__defines\targeting.dm" #include "code\__defines\tick.dm" #include "code\__defines\turfs.dm" From fb92653ac9a56d177277a7470134b310f802dc55 Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 7 Jun 2017 18:26:28 -0400 Subject: [PATCH 4/5] Ports "Makes global master vars static" * https://github.com/tgstation/tgstation/pull/27523 --- code/__defines/MC.dm | 8 +++---- code/__defines/tick.dm | 2 +- code/_helpers/time.dm | 2 +- code/controllers/master.dm | 44 +++++++++++++++++++------------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm index 297f04c148..fb15a693bf 100644 --- a/code/__defines/MC.dm +++ b/code/__defines/MC.dm @@ -1,13 +1,13 @@ -#define MC_TICK_CHECK ( ( world.tick_usage > CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 ) +#define MC_TICK_CHECK ( ( world.tick_usage > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 ) // Used for splitting up your remaining time into phases, if you want to evenly divide it. -#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count +#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count #define MC_SPLIT_TICK \ if(split_tick_phases > 1){\ - CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\ + Master.current_ticklimit = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\ --split_tick_phases;\ } else {\ - CURRENT_TICKLIMIT = original_tick_limit;\ + Master.current_ticklimit = original_tick_limit;\ } // Used to smooth out costs to try and avoid oscillation. diff --git a/code/__defines/tick.dm b/code/__defines/tick.dm index 3fa6e21bf3..4c88fd643e 100644 --- a/code/__defines/tick.dm +++ b/code/__defines/tick.dm @@ -3,5 +3,5 @@ #define TICK_LIMIT_MC 70 #define TICK_LIMIT_MC_INIT_DEFAULT 98 -#define TICK_CHECK ( world.tick_usage > CURRENT_TICKLIMIT ) +#define TICK_CHECK ( world.tick_usage > Master.current_ticklimit ) #define CHECK_TICK if TICK_CHECK stoplag() diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index b3989a32a4..3a6bcedcd1 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -120,4 +120,4 @@ var/round_start_time = 0 . += round(i*DELTA_CALC) sleep(i*world.tick_lag*DELTA_CALC) i *= 2 - while (world.tick_usage > min(TICK_LIMIT_TO_RUN, CURRENT_TICKLIMIT)) + while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit)) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 6bcfb6ff0a..7c2bc86a65 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -7,14 +7,6 @@ * **/ var/datum/controller/master/Master = new() -var/MC_restart_clear = 0 -var/MC_restart_timeout = 0 -var/MC_restart_count = 0 - - -//current tick limit, assigned by the queue controller before running a subsystem. -//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits -var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING /datum/controller/master name = "Master" @@ -52,6 +44,14 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING var/current_runlevel //for scheduling different subsystems for different stages of the round + var/static/restart_clear = 0 + var/static/restart_timeout = 0 + var/static/restart_count = 0 + + //current tick limit, assigned before running a subsystem. + //used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits + var/static/current_ticklimit = TICK_LIMIT_RUNNING + /datum/controller/master/New() // Highlander-style: there can only be one! Kill off the old and replace it with the new. subsystems = list() @@ -79,14 +79,14 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING // -1 if we encountered a runtime trying to recreate it /proc/Recreate_MC() . = -1 //so if we runtime, things know we failed - if (world.time < MC_restart_timeout) + if (world.time < Master.restart_timeout) return 0 - if (world.time < MC_restart_clear) - MC_restart_count *= 0.5 + if (world.time < Master.restart_clear) + Master.restart_count *= 0.5 - var/delay = 50 * ++MC_restart_count - MC_restart_timeout = world.time + delay - MC_restart_clear = world.time + (delay * 2) + var/delay = 50 * ++Master.restart_count + Master.restart_timeout = world.time + delay + Master.restart_clear = world.time + (delay * 2) Master.processing = 0 //stop ticking this one try new/datum/controller/master() @@ -155,13 +155,13 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING var/start_timeofday = REALTIMEOFDAY // Initialize subsystems. - CURRENT_TICKLIMIT = config.tick_limit_mc_init + current_ticklimit = config.tick_limit_mc_init for (var/datum/controller/subsystem/SS in subsystems) if (SS.flags & SS_NO_INIT) continue SS.Initialize(REALTIMEOFDAY) CHECK_TICK - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING var/time = (REALTIMEOFDAY - start_timeofday) / 10 var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!" @@ -268,7 +268,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING while (1) tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag))) if (processing <= 0) - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue @@ -276,7 +276,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING // because sleeps are processed in the order received, so longer sleeps are more likely to run first if (world.tick_usage > TICK_LIMIT_MC) sleep_delta += 2 - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5) + current_ticklimit = TICK_LIMIT_RUNNING * 0.5 sleep(world.tick_lag * (processing + sleep_delta)) continue @@ -314,7 +314,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING if (!error_level) iteration++ error_level++ - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue @@ -326,7 +326,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING if (!error_level) iteration++ error_level++ - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue error_level-- @@ -337,7 +337,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING iteration++ last_run = world.time src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta) - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc. + current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc. sleep(world.tick_lag * (processing + sleep_delta)) @@ -426,7 +426,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING else tick_precentage = tick_remaining - CURRENT_TICKLIMIT = world.tick_usage + tick_precentage + current_ticklimit = world.tick_usage + tick_precentage if (!(queue_node_flags & SS_TICKER)) ran_non_ticker = TRUE From 82e6049821a7ab346f7550d0c26016c3d50bf788 Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 7 Jun 2017 17:51:47 -0400 Subject: [PATCH 5/5] Actually hooks up the StonedMC to run its subsystems in Polaris * Hooks up informing Master the gameticker actually starts and stops the round subsystems will actually fire! What ho! * We should convert the gameticker as an MC subsystem someday, and probably completely rewrite it while we are at it becuase it is crazy. But this should bridge the gap until then. --- code/controllers/Processes/ticker.dm | 6 +++++- code/game/gamemodes/gameticker.dm | 7 +++++++ code/modules/admin/admin.dm | 1 + code/unit_tests/unit_test.dm | 1 + code/world.dm | 1 + 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/code/controllers/Processes/ticker.dm b/code/controllers/Processes/ticker.dm index 6fa6d43237..a70bb74c5f 100644 --- a/code/controllers/Processes/ticker.dm +++ b/code/controllers/Processes/ticker.dm @@ -34,5 +34,9 @@ var/global/datum/controller/process/ticker/tickerProcess /datum/controller/process/ticker/proc/getLastTickerTimeDuration() return lastTickerTimeDuration -/world/proc/has_round_started() +// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem! +/datum/controller/process/ticker/proc/HasRoundStarted() return (ticker && ticker.current_state >= GAME_STATE_PLAYING) + +/datum/controller/process/ticker/proc/IsRoundInProgress() + return (ticker && ticker.current_state == GAME_STATE_PLAYING) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 9e4dff2ce5..4567a1da51 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -62,6 +62,7 @@ var/global/datum/controller/gameticker/ticker vote.process() if(pregame_timeleft <= 0) current_state = GAME_STATE_SETTING_UP + Master.SetRunLevel(RUNLEVEL_SETUP) while (!setup()) @@ -74,6 +75,7 @@ var/global/datum/controller/gameticker/ticker if((master_mode=="random") || (master_mode=="secret")) if(!runnable_modes.len) current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) world << "Unable to choose playable game mode. Reverting to pre-game lobby." return 0 if(secret_force_mode != "secret") @@ -88,6 +90,7 @@ var/global/datum/controller/gameticker/ticker if(!src.mode) current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) world << "Serious error in mode setup! Reverting to pre-game lobby." return 0 @@ -99,6 +102,7 @@ var/global/datum/controller/gameticker/ticker if(!src.mode.can_start()) world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby." current_state = GAME_STATE_PREGAME + Master.SetRunLevel(RUNLEVEL_LOBBY) mode.fail_setup() mode = null job_master.ResetOccupations() @@ -127,6 +131,7 @@ var/global/datum/controller/gameticker/ticker shuttle_controller.setup_shuttle_docks() + // TODO - Leshana - Dear God Fix This. Fix all of this. Not just this line, this entire proc. This entire file! spawn(0)//Forking here so we dont have to wait for this to finish mode.post_setup() //Cleanup some stuff @@ -155,6 +160,7 @@ var/global/datum/controller/gameticker/ticker */ processScheduler.start() + Master.SetRunLevel(RUNLEVEL_GAME) if(config.sql_enabled) statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE @@ -319,6 +325,7 @@ var/global/datum/controller/gameticker/ticker if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game)) current_state = GAME_STATE_FINISHED + Master.SetRunLevel(RUNLEVEL_POSTGAME) spawn declare_completion() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index aea165e063..2f9bca5f01 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -783,6 +783,7 @@ proc/admin_notice(var/message, var/rights) return if(ticker.current_state == GAME_STATE_PREGAME) ticker.current_state = GAME_STATE_SETTING_UP + Master.SetRunLevel(RUNLEVEL_SETUP) log_admin("[usr.key] has started the game.") message_admins("[usr.key] has started the game.") feedback_add_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/unit_tests/unit_test.dm b/code/unit_tests/unit_test.dm index f05514ce74..605cf8fcac 100644 --- a/code/unit_tests/unit_test.dm +++ b/code/unit_tests/unit_test.dm @@ -45,6 +45,7 @@ var/total_unit_tests = 0 sleep(1) ticker.current_state = GAME_STATE_SETTING_UP + Master.SetRunLevel(RUNLEVEL_SETUP) log_unit_test("Round has been started. Waiting 10 seconds to start tests.") sleep(100) diff --git a/code/world.dm b/code/world.dm index a11d875c51..9a031dda0f 100644 --- a/code/world.dm +++ b/code/world.dm @@ -433,6 +433,7 @@ var/world_topic_spam_protect_time = world.timeofday */ processScheduler.stop() + Master.Shutdown() //run SS shutdowns for(var/client/C in clients) if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite