diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm index 115748a9a82..ec1a3ebbb13 100644 --- a/code/__DEFINES/MC.dm +++ b/code/__DEFINES/MC.dm @@ -33,7 +33,7 @@ /// Returns true if the MC is initialized and running. /// Optional argument init_stage controls what stage the mc must have initialized to count as initialized. Defaults to INITSTAGE_MAX if not specified. -#define MC_RUNNING(INIT_STAGE...) (Master && Master.processing > 0 && Master.current_runlevel && Master.init_stage_completed == (max(min(INITSTAGE_MAX, ##INIT_STAGE), 1))) +#define MC_RUNNING(INIT_STAGE...) (Master && Master.processing > 0 && Master.current_runlevel && Master.init_stage_completed >= (max(min(INITSTAGE_MAX, ##INIT_STAGE), 1))) #define MC_LOOP_RTN_NEWSTAGES 1 #define MC_LOOP_RTN_GRACEFUL_EXIT 2 @@ -83,9 +83,11 @@ #define SS_PAUSING 5 /// in the middle of pausing // Subsystem init stages -#define INITSTAGE_EARLY 1 //! Early init stuff that doesn't need to wait for mapload -#define INITSTAGE_MAIN 2 //! Main init stage -#define INITSTAGE_MAX 2 //! Highest initstage. +#define INITSTAGE_FIRST 1 +#define INITSTAGE_EARLY 2 //! Early init stuff that doesn't need to wait for mapload +#define INITSTAGE_MAIN 3 //! Main init stage +#define INITSTAGE_LAST 4 +#define INITSTAGE_MAX 4 //! Highest initstage. #define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\ /datum/controller/subsystem/##X/New(){\ diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 3354f6306d3..3a4956de758 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -125,73 +125,6 @@ /// Successfully initialized, BUT do not announce it to players (generally to hide game mechanics it would otherwise spoil) #define SS_INIT_NO_MESSAGE 4 -//! ### SS initialization load orders -// Subsystem init_order, from highest priority to lowest priority -// Subsystems shutdown in the reverse of the order they initialize in -// The numbers just define the ordering, they are meaningless otherwise. - -#define INIT_ORDER_PROFILER 101 -#define INIT_ORDER_TITLE 100 -#define INIT_ORDER_GARBAGE 99 -#define INIT_ORDER_DBCORE 95 -#define INIT_ORDER_BLACKBOX 94 -#define INIT_ORDER_SERVER_MAINT 93 -#define INIT_ORDER_INPUT 85 -#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins can't do much without it -#define INIT_ORDER_SOUNDS 83 -#define INIT_ORDER_INSTRUMENTS 82 -#define INIT_ORDER_GREYSCALE 81 -#define INIT_ORDER_VIS 80 -#define INIT_ORDER_SECURITY_LEVEL 79 // We need to load before events so that it has a security level to choose from. -#define INIT_ORDER_DISCORD 78 -#define INIT_ORDER_ACHIEVEMENTS 77 -#define INIT_ORDER_STATION 74 //This is high priority because it manipulates a lot of the subsystems that will initialize after it. -#define INIT_ORDER_QUIRKS 73 -#define INIT_ORDER_REAGENTS 72 //HAS to be before mapping and assets - both create objects, which creates reagents, which relies on lists made in this subsystem -#define INIT_ORDER_EVENTS 70 -#define INIT_ORDER_IDACCESS 66 -#define INIT_ORDER_JOBS 65 // Must init before atoms, to set up properly the dynamic job lists. -#define INIT_ORDER_AI_MOVEMENT 56 //We need the movement setup -#define INIT_ORDER_AI_CONTROLLERS 55 //So the controller can get the ref -#define INIT_ORDER_TICKER 55 -#define INIT_ORDER_TCG 55 -#define INIT_ORDER_MAPPING 50 -#define INIT_ORDER_AI_IDLE_CONTROLLERS 50 -#define INIT_ORDER_EARLY_ASSETS 48 -#define INIT_ORDER_RESEARCH 47 -#define INIT_ORDER_TIMETRACK 46 -#define INIT_ORDER_SPATIAL_GRID 43 -#define INIT_ORDER_ECONOMY 40 -#define INIT_ORDER_OUTPUTS 35 -#define INIT_ORDER_RESTAURANT 34 -#define INIT_ORDER_TTS 33 -#define INIT_ORDER_FLUIDS 32 // Needs to be above atoms, as some atoms may want to start fluids/gases on init -#define INIT_ORDER_ATOMS 30 -#define INIT_ORDER_LANGUAGE 25 -#define INIT_ORDER_MACHINES 20 -#define INIT_ORDER_SKILLS 15 -#define INIT_ORDER_QUEUELINKS 10 -#define INIT_ORDER_TIMER 1 -#define INIT_ORDER_DEFAULT 0 -#define INIT_ORDER_AIR -1 -#define INIT_ORDER_PERSISTENCE -2 -#define INIT_ORDER_PERSISTENT_PAINTINGS -3 // Assets relies on this -#define INIT_ORDER_VOTE -4 // Needs to be after persistence so that recent maps are not loaded. -#define INIT_ORDER_ASSETS -5 -#define INIT_ORDER_ICON_SMOOTHING -6 -#define INIT_ORDER_OVERLAY -7 -#define INIT_ORDER_XKEYSCORE -10 -#define INIT_ORDER_STICKY_BAN -10 -#define INIT_ORDER_LIGHTING -20 -#define INIT_ORDER_SHUTTLE -21 -#define INIT_ORDER_MINOR_MAPPING -40 -#define INIT_ORDER_PATH -50 -#define INIT_ORDER_EXPLOSIONS -69 -#define INIT_ORDER_STATPANELS -97 -#define INIT_ORDER_BAN_CACHE -98 -#define INIT_ORDER_INIT_PROFILER -99 //Near the end, logs the costs of initialize -#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. - // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_UNPLANNED_NPC 3 diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index f333318c94e..ead1b5cbff5 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -65,7 +65,10 @@ return cmp_numeric_asc(a.get_exp_living(TRUE), b.get_exp_living(TRUE)) /proc/cmp_subsystem_init(datum/controller/subsystem/a, datum/controller/subsystem/b) - return initial(b.init_order) - initial(a.init_order) //uses initial() so it can be used on types + return a.init_order - b.init_order + +/proc/cmp_subsystem_init_stage(datum/controller/subsystem/a, datum/controller/subsystem/b) + return initial(a.init_stage) - initial(b.init_stage) /proc/cmp_subsystem_display(datum/controller/subsystem/a, datum/controller/subsystem/b) return sorttext(b.name, a.name) diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index f796bd5480a..f6457338040 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -152,7 +152,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) /proc/recover_all_SS_and_recreate_master() del(Master) var/list/subsytem_types = subtypesof(/datum/controller/subsystem) - sortTim(subsytem_types, GLOBAL_PROC_REF(cmp_subsystem_init)) + sortTim(subsytem_types, GLOBAL_PROC_REF(cmp_subsystem_init_stage)) for(var/I in subsytem_types) new I . = Recreate_MC() diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 55160ec6504..0c85b980278 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -110,7 +110,7 @@ GLOBAL_REAL(Master, /datum/controller/master) //Code used for first master on game boot or if existing master got deleted Master = src var/list/subsystem_types = subtypesof(/datum/controller/subsystem) - sortTim(subsystem_types, GLOBAL_PROC_REF(cmp_subsystem_init)) + sortTim(subsystem_types, GLOBAL_PROC_REF(cmp_subsystem_init_stage)) //Find any abandoned subsystem from the previous master (if there was any) var/list/existing_subsystems = list() @@ -333,10 +333,90 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie for (var/i in 1 to INITSTAGE_MAX) stage_sorted_subsystems[i] = list() - // Sort subsystems by init_order, so they initialize in the correct order. - sortTim(subsystems, GLOBAL_PROC_REF(cmp_subsystem_init)) + var/list/type_to_subsystem = list() + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + type_to_subsystem[subsystem.type] = subsystem - for (var/datum/controller/subsystem/subsystem as anything in subsystems) + // 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) + if(!ispath(dependent_type, /datum/controller/subsystem)) + stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an invalid dependent: `[dependent_type]`. Skipping") + continue + var/datum/controller/subsystem/dependent = type_to_subsystem[dependent_type] + dependent.dependencies |= subsystem.type + subsystem.dependents = list() + + // Constructs a reverse-dependency graph. + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + for(var/dependency_type as anything 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 + var/datum/controller/subsystem/dependency = type_to_subsystem[dependency_type] + // Not a foolproof failsafe, likely to only prevent any immediate issues if this is only triggered once. + if(subsystem.init_stage < dependency.init_stage) + stack_trace("ERROR: MC: subsystem `[subsystem.type]` has an init_stage before one of its dependencies (Dependency: `[dependency.type]`, [subsystem.init_stage] < [dependency.init_stage])! Setting init_stage to [dependency.init_stage]") + subsystem.init_stage = dependency.init_stage + dependency.dependents += subsystem + + // Topological sorting algorithm + var/list/counts = new(subsystems.len) + var/list/unsorted_subsystems = list() + var/index = 1 + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + counts[index] = length(subsystem.dependencies) + subsystem.ordering_id = index + if(counts[index] == 0) + unsorted_subsystems += subsystem + index += 1 + + var/list/sorted_subsystems = list() + while(length(unsorted_subsystems) > 0) + var/datum/controller/subsystem/sub = unsorted_subsystems[unsorted_subsystems.len] + unsorted_subsystems.len-- + sorted_subsystems += sub + for(var/datum/controller/subsystem/dependent as anything in sub.dependents) + counts[dependent.ordering_id] -= 1 + if(counts[dependent.ordering_id] == 0) + unsorted_subsystems += dependent + // Topological sorting algorithm end + + if(length(subsystems) != length(sorted_subsystems)) + var/list/circular_dependency = subsystems.Copy() - 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]" + + var/list/datum/controller/subsystem/nodes = list(circular_dependency[1]) + var/list/loop = list() + while(length(nodes) > 0) + var/datum/controller/subsystem/node = nodes[nodes.len] + nodes.len-- + if(node in loop) + loop += node + break + loop += node + for(var/datum/controller/subsystem/connected as anything in node.dependencies) + nodes += type_to_subsystem[connected] + + var/loop_position = 0 + for(var/datum/controller/subsystem/node in loop) + if(node == loop[loop.len]) + break + loop_position++ + if(loop_position != 0) + loop.Cut(1, loop_position + 1) + + for(var/datum/controller/subsystem/subsystem as anything in loop) + debug_msg += "[subsystem.name]" + + // Can't initialize them if they have circular dependencies, there's no real failsafe here. + stack_trace("ERROR: CRITICAL: MC: The following subsystems have circular dependencies: [jointext(debug_msg, " -> ")]") + to_chat(world, span_bolddanger("CRITICAL: Failed to initialize [jointext(usr_msg, ", ")]"), MESSAGE_TYPE_DEBUG) + + for (var/datum/controller/subsystem/subsystem as anything in sorted_subsystems) var/subsystem_init_stage = subsystem.init_stage if (!isnum(subsystem_init_stage) || subsystem_init_stage < 1 || subsystem_init_stage > INITSTAGE_MAX || round(subsystem_init_stage) != subsystem_init_stage) stack_trace("ERROR: MC: subsystem `[subsystem.type]` has invalid init_stage: `[subsystem_init_stage]`. Setting to `[INITSTAGE_MAX]`") @@ -344,12 +424,15 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie stage_sorted_subsystems[subsystem_init_stage] += subsystem // Sort subsystems by display setting for easy access. + var/evaluated_order = 1 sortTim(subsystems, GLOBAL_PROC_REF(cmp_subsystem_display)) var/start_timeofday = REALTIMEOFDAY for (var/current_init_stage in 1 to INITSTAGE_MAX) // Initialize subsystems. for (var/datum/controller/subsystem/subsystem in stage_sorted_subsystems[current_init_stage]) + subsystem.init_order = evaluated_order + evaluated_order++ init_subsystem(subsystem) CHECK_TICK diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 4bde26e3c9d..0dbe2af2f8b 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -13,8 +13,20 @@ /// Name of the subsystem - you must change this name = "fire coderbus" - /// Order of initialization. Higher numbers are initialized first, lower numbers later. Use or create defines such as [INIT_ORDER_DEFAULT] so we can see the order in one file. - var/init_order = INIT_ORDER_DEFAULT + /// Determines which subsystems this subsystem is dependant on to initialize. Will initialize after all specified subsystems. + /// If init_stage is earlier than a dependent subsystem, will throw an error and push the init stage forward to that subsystem. + /// Usage: Put the typepaths of the subsystems that need to init before this one in this list. + var/list/dependencies = list() + + /// The inverse of the dependencies. Can be set manually, but will also get evaluated at runtime. Turns into a list of instances at runtime. + /// Usage: Put the typepaths of the subsystems that need to init after this one in this list. + var/list/dependents + + /// ID of the subsystem. Set automatically when the dependency graph is evaluated. Used primarily in determining order. + var/ordering_id = 0 + + /// Do not modify. Automatically set when the dependency graph is evaluated. Similar to ordering_id, but evaluated after init_stage. + var/init_order = 0 /// Time to wait (in deciseconds) between each call to fire(). Must be a positive integer. var/wait = 20 diff --git a/code/controllers/subsystem/achievements.dm b/code/controllers/subsystem/achievements.dm index 6a1cc5dd8bd..4633be6f741 100644 --- a/code/controllers/subsystem/achievements.dm +++ b/code/controllers/subsystem/achievements.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(achievements) name = "Achievements" flags = SS_NO_FIRE - init_order = INIT_ORDER_ACHIEVEMENTS var/achievements_enabled = FALSE ///List of achievements diff --git a/code/controllers/subsystem/admin_verbs.dm b/code/controllers/subsystem/admin_verbs.dm index 9496b95d998..645a447c485 100644 --- a/code/controllers/subsystem/admin_verbs.dm +++ b/code/controllers/subsystem/admin_verbs.dm @@ -3,7 +3,7 @@ GENERAL_PROTECT_DATUM(/datum/controller/subsystem/admin_verbs) SUBSYSTEM_DEF(admin_verbs) name = "Admin Verbs" flags = SS_NO_FIRE - init_order = INIT_ORDER_ADMIN_VERBS + init_stage = INITSTAGE_EARLY /// A list of all admin verbs indexed by their type. var/list/datum/admin_verb/admin_verbs_by_type = list() /// A list of all admin verbs indexed by their visibility flag. diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 8a5eb43bfc9..c5123f48af6 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -3,7 +3,9 @@ SUBSYSTEM_DEF(ai_controllers) name = "AI Controller Ticker" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_NPC - init_order = INIT_ORDER_AI_CONTROLLERS + dependencies = list( + /datum/controller/subsystem/movement/ai_movement + ) wait = 0.5 SECONDS //Plan every half second if required, not great not terrible. runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME ///type of status we are interested in running diff --git a/code/controllers/subsystem/ai_idle_controllers.dm b/code/controllers/subsystem/ai_idle_controllers.dm index 367a2c82ffc..a36901ceac6 100644 --- a/code/controllers/subsystem/ai_idle_controllers.dm +++ b/code/controllers/subsystem/ai_idle_controllers.dm @@ -2,7 +2,9 @@ AI_CONTROLLER_SUBSYSTEM_DEF(ai_idle_controllers) name = "AI Idle Controllers" flags = SS_POST_FIRE_TIMING | SS_BACKGROUND priority = FIRE_PRIORITY_IDLE_NPC - init_order = INIT_ORDER_AI_IDLE_CONTROLLERS + dependencies = list( + /datum/controller/subsystem/ai_controllers + ) wait = 5 SECONDS runlevels = RUNLEVEL_GAME planning_status = AI_STATUS_IDLE diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 34e71209f19..a2a73f2b667 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -1,6 +1,9 @@ SUBSYSTEM_DEF(air) name = "Atmospherics" - init_order = INIT_ORDER_AIR + dependencies = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms + ) priority = FIRE_PRIORITY_AIR wait = 0.5 SECONDS flags = SS_BACKGROUND diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 8336c60c0fa..79d2e312a21 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -1,6 +1,10 @@ SUBSYSTEM_DEF(assets) name = "Assets" - init_order = INIT_ORDER_ASSETS + dependencies = list( + /datum/controller/subsystem/atoms, + /datum/controller/subsystem/persistent_paintings, + /datum/controller/subsystem/processing/greyscale + ) flags = SS_NO_FIRE var/list/datum/asset_cache_item/cache = list() var/list/preload = list() diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 7f26e4d0414..c1b2e86403a 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -1,6 +1,11 @@ SUBSYSTEM_DEF(atoms) name = "Atoms" - init_order = INIT_ORDER_ATOMS + dependencies = list( + /datum/controller/subsystem/processing/reagents, + /datum/controller/subsystem/fluids, + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/job + ) flags = SS_NO_FIRE /// A stack of list(source, desired initialized state) diff --git a/code/controllers/subsystem/ban_cache.dm b/code/controllers/subsystem/ban_cache.dm index 2d10baecab3..21e1a92a7ed 100644 --- a/code/controllers/subsystem/ban_cache.dm +++ b/code/controllers/subsystem/ban_cache.dm @@ -4,7 +4,7 @@ SUBSYSTEM_DEF(ban_cache) /datum/controller/subsystem/ban_cache name = "Ban Cache" - init_order = INIT_ORDER_BAN_CACHE + init_stage = INITSTAGE_LAST flags = SS_NO_FIRE var/query_started = FALSE diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 628b192b72c..453eb073e80 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -2,7 +2,6 @@ SUBSYSTEM_DEF(blackbox) name = "Blackbox" wait = 6000 runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - init_order = INIT_ORDER_BLACKBOX var/list/feedback_list = list() //list of datum/feedback_variable var/list/first_death = list() //the first death of this round, assoc. vars keep track of different things diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index f93ab6e09f6..d2303074077 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -8,7 +8,7 @@ SUBSYSTEM_DEF(chat) flags = SS_TICKER|SS_NO_INIT wait = 1 priority = FIRE_PRIORITY_CHAT - init_order = INIT_ORDER_CHAT + init_stage = INITSTAGE_LAST /// Assosciates a ckey with a list of messages to send to them. var/list/list/datum/chat_payload/client_to_payloads = list() diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm index 805fe419c94..c98009ed9d9 100644 --- a/code/controllers/subsystem/dbcore.dm +++ b/code/controllers/subsystem/dbcore.dm @@ -2,9 +2,9 @@ SUBSYSTEM_DEF(dbcore) name = "Database" flags = SS_TICKER + init_stage = INITSTAGE_FIRST wait = 10 // Not seconds because we're running on SS_TICKER runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT - init_order = INIT_ORDER_DBCORE priority = FIRE_PRIORITY_DATABASE var/schema_mismatch = 0 @@ -49,6 +49,8 @@ SUBSYSTEM_DEF(dbcore) var/db_daemon_started = FALSE /datum/controller/subsystem/dbcore/Initialize() + Connect() + //We send warnings to the admins during subsystem init, as the clients will be New'd and messages //will queue properly with goonchat switch(schema_mismatch) diff --git a/code/controllers/subsystem/discord.dm b/code/controllers/subsystem/discord.dm index be9f066cf83..802b95b2341 100644 --- a/code/controllers/subsystem/discord.dm +++ b/code/controllers/subsystem/discord.dm @@ -31,7 +31,7 @@ SUBSYSTEM_DEF(discord) name = "Discord" wait = 3000 - init_order = INIT_ORDER_DISCORD + init_stage = INITSTAGE_EARLY /// People to save to notify file var/list/notify_members = list() diff --git a/code/controllers/subsystem/early_assets.dm b/code/controllers/subsystem/early_assets.dm index 5ce669bec83..d40ea8614d0 100644 --- a/code/controllers/subsystem/early_assets.dm +++ b/code/controllers/subsystem/early_assets.dm @@ -5,7 +5,15 @@ /// opened it up early. SUBSYSTEM_DEF(early_assets) name = "Early Assets" - init_order = INIT_ORDER_EARLY_ASSETS + dependencies = list( + /datum/controller/subsystem/processing/reagents, + /datum/controller/subsystem/processing/greyscale + ) + dependents = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms + ) + init_stage = INITSTAGE_EARLY flags = SS_NO_FIRE /datum/controller/subsystem/early_assets/Initialize() diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm index 25876fd80c6..4a519d0da34 100644 --- a/code/controllers/subsystem/economy.dm +++ b/code/controllers/subsystem/economy.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(economy) name = "Economy" wait = 5 MINUTES - init_order = INIT_ORDER_ECONOMY runlevels = RUNLEVEL_GAME ///How many paychecks should players start out the round with? var/roundstart_paychecks = 5 diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm index 3451ad506c9..e7aaac4159c 100644 --- a/code/controllers/subsystem/events.dm +++ b/code/controllers/subsystem/events.dm @@ -1,6 +1,8 @@ SUBSYSTEM_DEF(events) name = "Events" - init_order = INIT_ORDER_EVENTS + dependencies = list( + /datum/controller/subsystem/processing/station + ) runlevels = RUNLEVEL_GAME ///list of all datum/round_event_control. Used for selecting events based on weight and occurrences. var/list/control = list() diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index 36dbba09eae..c51d70a1de2 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -7,7 +7,6 @@ GLOBAL_LIST_EMPTY(explosions) SUBSYSTEM_DEF(explosions) name = "Explosions" - init_order = INIT_ORDER_EXPLOSIONS priority = FIRE_PRIORITY_EXPLOSIONS wait = 1 flags = SS_TICKER|SS_NO_INIT diff --git a/code/controllers/subsystem/fluids.dm b/code/controllers/subsystem/fluids.dm index 2b4ce472956..6b68ae71722 100644 --- a/code/controllers/subsystem/fluids.dm +++ b/code/controllers/subsystem/fluids.dm @@ -22,7 +22,6 @@ SUBSYSTEM_DEF(fluids) wait = 0 // Will be autoset to whatever makes the most sense given the spread and effect waits. flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME - init_order = INIT_ORDER_FLUIDS priority = FIRE_PRIORITY_FLUIDS // Fluid spread processing: diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index f6b1bc3f860..844f52a860f 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -27,8 +27,7 @@ SUBSYSTEM_DEF(garbage) wait = 2 SECONDS flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY - init_order = INIT_ORDER_GARBAGE - init_stage = INITSTAGE_EARLY + init_stage = INITSTAGE_FIRST var/list/collection_timeout = list(GC_FILTER_QUEUE, GC_CHECK_QUEUE, GC_DEL_QUEUE) // deciseconds to wait before moving something up in the queue to the next level diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm index 9e5e9ffa99d..e157e925a11 100644 --- a/code/controllers/subsystem/icon_smooth.dm +++ b/code/controllers/subsystem/icon_smooth.dm @@ -1,6 +1,8 @@ SUBSYSTEM_DEF(icon_smooth) name = "Icon Smoothing" - init_order = INIT_ORDER_ICON_SMOOTHING + dependencies = list( + /datum/controller/subsystem/atoms + ) wait = 1 priority = FIRE_PRIORITY_SMOOTHING flags = SS_TICKER diff --git a/code/controllers/subsystem/id_access.dm b/code/controllers/subsystem/id_access.dm index 1a94a13389d..49e12498c8d 100644 --- a/code/controllers/subsystem/id_access.dm +++ b/code/controllers/subsystem/id_access.dm @@ -3,7 +3,6 @@ */ SUBSYSTEM_DEF(id_access) name = "IDs and Access" - init_order = INIT_ORDER_IDACCESS flags = SS_NO_FIRE /// Dictionary of access flags. Keys are accesses. Values are their associated bitflags. diff --git a/code/controllers/subsystem/init_profiler.dm b/code/controllers/subsystem/init_profiler.dm index 063898b6a09..dcb163e596a 100644 --- a/code/controllers/subsystem/init_profiler.dm +++ b/code/controllers/subsystem/init_profiler.dm @@ -4,8 +4,7 @@ ///Hopefully this makes sorting out what causes problems when easier SUBSYSTEM_DEF(init_profiler) name = "Init Profiler" - init_order = INIT_ORDER_INIT_PROFILER - init_stage = INITSTAGE_MAX + init_stage = INITSTAGE_LAST flags = SS_NO_FIRE /datum/controller/subsystem/init_profiler/Initialize() diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index e4e12418a75..a2a43f79a90 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -1,6 +1,5 @@ VERB_MANAGER_SUBSYSTEM_DEF(input) name = "Input" - init_order = INIT_ORDER_INPUT init_stage = INITSTAGE_EARLY flags = SS_TICKER priority = FIRE_PRIORITY_INPUT diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm index 3ae9cfab0c5..286de507abc 100644 --- a/code/controllers/subsystem/ipintel.dm +++ b/code/controllers/subsystem/ipintel.dm @@ -1,6 +1,5 @@ SUBSYSTEM_DEF(ipintel) name = "XKeyScore" - init_order = INIT_ORDER_XKEYSCORE flags = SS_NO_INIT|SS_NO_FIRE /// The threshold for probability to be considered a VPN and/or bad IP var/probability_threshold diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index ad264e3d4f0..a1479f7c7a0 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -1,6 +1,8 @@ SUBSYSTEM_DEF(job) name = "Jobs" - init_order = INIT_ORDER_JOBS + dependencies = list( + /datum/controller/subsystem/processing/station + ) flags = SS_NO_FIRE /// List of all jobs. diff --git a/code/controllers/subsystem/library.dm b/code/controllers/subsystem/library.dm index bfe77f70f02..fc08e95ba84 100644 --- a/code/controllers/subsystem/library.dm +++ b/code/controllers/subsystem/library.dm @@ -1,6 +1,10 @@ /// Manages library data, loading bookselves, etc SUBSYSTEM_DEF(library) name = "Library Loading" + dependencies = list( + /datum/controller/subsystem/atoms, + /datum/controller/subsystem/mapping + ) flags = SS_NO_FIRE /// List of bookselves to prefill with books diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 24d871d2f09..c4fca37ca7b 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -1,7 +1,10 @@ SUBSYSTEM_DEF(lighting) name = "Lighting" + dependencies = list( + /datum/controller/subsystem/atoms, + /datum/controller/subsystem/mapping + ) wait = 2 - init_order = INIT_ORDER_LIGHTING flags = SS_TICKER var/static/list/sources_queue = list() // List of lighting sources queued for update. var/static/list/corners_queue = list() // List of lighting corners queued for update. diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index a9950f1f4d8..0a6cb90d5d4 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -1,6 +1,8 @@ SUBSYSTEM_DEF(machines) name = "Machines" - init_order = INIT_ORDER_MACHINES + dependencies = list( + /datum/controller/subsystem/atoms + ) flags = SS_KEEP_TIMING wait = 2 SECONDS diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index b4184f8a34d..16ff85ead53 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -1,6 +1,10 @@ SUBSYSTEM_DEF(mapping) name = "Mapping" - init_order = INIT_ORDER_MAPPING + dependencies = list( + /datum/controller/subsystem/job, + /datum/controller/subsystem/processing/station, + /datum/controller/subsystem/processing/reagents + ) runlevels = ALL var/list/nuke_tiles = list() diff --git a/code/controllers/subsystem/market.dm b/code/controllers/subsystem/market.dm index 00903cbf654..7a044964ee1 100644 --- a/code/controllers/subsystem/market.dm +++ b/code/controllers/subsystem/market.dm @@ -1,7 +1,9 @@ SUBSYSTEM_DEF(market) name = "Market" flags = SS_BACKGROUND - init_order = INIT_ORDER_DEFAULT + dependencies = list( + /datum/controller/subsystem/atoms + ) /// Descriptions for each shipping methods. var/shipping_method_descriptions = list( diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index 4aed29be350..cdd4d66e695 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -3,7 +3,10 @@ SUBSYSTEM_DEF(minor_mapping) name = "Minor Mapping" - init_order = INIT_ORDER_MINOR_MAPPING + dependencies = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms, + ) flags = SS_NO_FIRE /datum/controller/subsystem/minor_mapping/Initialize() diff --git a/code/controllers/subsystem/movement/ai_movement.dm b/code/controllers/subsystem/movement/ai_movement.dm index db0b987eb31..90333b529d7 100644 --- a/code/controllers/subsystem/movement/ai_movement.dm +++ b/code/controllers/subsystem/movement/ai_movement.dm @@ -4,7 +4,6 @@ MOVEMENT_SUBSYSTEM_DEF(ai_movement) flags = SS_BACKGROUND|SS_TICKER priority = FIRE_PRIORITY_NPC_MOVEMENT runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - init_order = INIT_ORDER_AI_MOVEMENT ///an assoc list of all ai_movement types. Assoc type to instance var/list/movement_types diff --git a/code/controllers/subsystem/ore_generation.dm b/code/controllers/subsystem/ore_generation.dm index e36dd577794..50560a0b3d4 100644 --- a/code/controllers/subsystem/ore_generation.dm +++ b/code/controllers/subsystem/ore_generation.dm @@ -2,7 +2,9 @@ SUBSYSTEM_DEF(ore_generation) name = "Ore Generation" wait = 60 SECONDS - init_order = INIT_ORDER_DEFAULT + dependencies = list( + /datum/controller/subsystem/atoms + ) runlevels = RUNLEVEL_GAME /// All ore vents that are currently producing boulders. diff --git a/code/controllers/subsystem/pathfinder.dm b/code/controllers/subsystem/pathfinder.dm index d95b3bff538..b67260853ba 100644 --- a/code/controllers/subsystem/pathfinder.dm +++ b/code/controllers/subsystem/pathfinder.dm @@ -1,7 +1,6 @@ /// Queues and manages JPS pathfinding steps SUBSYSTEM_DEF(pathfinder) name = "Pathfinder" - init_order = INIT_ORDER_PATH priority = FIRE_PRIORITY_PATHFINDING wait = 0.5 /// List of pathfind datums we are currently trying to process diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index 8d9bc483908..2f4f5ff704c 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -3,7 +3,10 @@ SUBSYSTEM_DEF(persistence) name = "Persistence" - init_order = INIT_ORDER_PERSISTENCE + dependencies = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms + ) flags = SS_NO_FIRE ///instantiated wall engraving components diff --git a/code/controllers/subsystem/persistent_paintings.dm b/code/controllers/subsystem/persistent_paintings.dm index b2f0921df6d..845653d0414 100644 --- a/code/controllers/subsystem/persistent_paintings.dm +++ b/code/controllers/subsystem/persistent_paintings.dm @@ -93,7 +93,6 @@ SUBSYSTEM_DEF(persistent_paintings) name = "Persistent Paintings" - init_order = INIT_ORDER_PERSISTENT_PAINTINGS flags = SS_NO_FIRE /// A list of painting frames that this controls diff --git a/code/controllers/subsystem/processing/ai_behaviors.dm b/code/controllers/subsystem/processing/ai_behaviors.dm index e92da2474bb..6c53d16e79f 100644 --- a/code/controllers/subsystem/processing/ai_behaviors.dm +++ b/code/controllers/subsystem/processing/ai_behaviors.dm @@ -4,7 +4,9 @@ PROCESSING_SUBSYSTEM_DEF(ai_behaviors) flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_NPC_ACTIONS runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - init_order = INIT_ORDER_AI_CONTROLLERS + dependencies = list( + /datum/controller/subsystem/movement/ai_movement + ) wait = 1 ///List of all ai_behavior singletons, key is the typepath while assigned value is a newly created instance of the typepath. See SetupAIBehaviors() var/list/ai_behaviors diff --git a/code/controllers/subsystem/processing/ai_idle_behaviors.dm b/code/controllers/subsystem/processing/ai_idle_behaviors.dm index 8875d971ad8..53a9465046e 100644 --- a/code/controllers/subsystem/processing/ai_idle_behaviors.dm +++ b/code/controllers/subsystem/processing/ai_idle_behaviors.dm @@ -3,7 +3,9 @@ PROCESSING_SUBSYSTEM_DEF(idle_ai_behaviors) flags = SS_BACKGROUND wait = 1.5 SECONDS priority = FIRE_PRIORITY_IDLE_NPC - init_order = INIT_ORDER_AI_IDLE_CONTROLLERS //must execute only after ai behaviors are initialized + dependencies = list( + /datum/controller/subsystem/ai_controllers + ) ///List of all the idle ai behaviors var/list/idle_behaviors = list() diff --git a/code/controllers/subsystem/processing/fishing.dm b/code/controllers/subsystem/processing/fishing.dm index abd31293ac0..8220421effe 100644 --- a/code/controllers/subsystem/processing/fishing.dm +++ b/code/controllers/subsystem/processing/fishing.dm @@ -1,6 +1,9 @@ /// subsystem for the fishing minigame processing. PROCESSING_SUBSYSTEM_DEF(fishing) name = "Fishing" + dependencies = list( + /datum/controller/subsystem/atoms + ) flags = SS_BACKGROUND wait = 0.05 SECONDS // If you raise it to 0.1 SECONDS, you better also modify [datum/fish_movement/move_fish()] ///A list of cached fish icons diff --git a/code/controllers/subsystem/processing/greyscale.dm b/code/controllers/subsystem/processing/greyscale.dm index 901a3bf930d..fcd7b482847 100644 --- a/code/controllers/subsystem/processing/greyscale.dm +++ b/code/controllers/subsystem/processing/greyscale.dm @@ -7,9 +7,8 @@ PROCESSING_SUBSYSTEM_DEF(greyscale) name = "Greyscale" flags = SS_BACKGROUND - init_order = INIT_ORDER_GREYSCALE wait = 3 SECONDS - + init_stage = INITSTAGE_EARLY var/list/datum/greyscale_config/configurations = list() var/list/datum/greyscale_layer/layer_types = list() #ifdef USE_RUSTG_ICONFORGE_GAGS diff --git a/code/controllers/subsystem/processing/instruments.dm b/code/controllers/subsystem/processing/instruments.dm index 1cfbb144e5f..fd486d419eb 100644 --- a/code/controllers/subsystem/processing/instruments.dm +++ b/code/controllers/subsystem/processing/instruments.dm @@ -1,7 +1,6 @@ PROCESSING_SUBSYSTEM_DEF(instruments) name = "Instruments" wait = 0.5 - init_order = INIT_ORDER_INSTRUMENTS flags = SS_KEEP_TIMING priority = FIRE_PRIORITY_INSTRUMENTS /// List of all instrument data, associative id = datum diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 43c84864ad9..f3300726029 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -47,7 +47,6 @@ GLOBAL_LIST_INIT(quirk_string_blacklist, generate_quirk_string_blacklist()) // - Quirk datums are stored and hold different effects, as well as being a vector for applying trait string PROCESSING_SUBSYSTEM_DEF(quirks) name = "Quirks" - init_order = INIT_ORDER_QUIRKS flags = SS_BACKGROUND runlevels = RUNLEVEL_GAME wait = 1 SECONDS diff --git a/code/controllers/subsystem/processing/reagents.dm b/code/controllers/subsystem/processing/reagents.dm index 503be4384f4..5e64e259db4 100644 --- a/code/controllers/subsystem/processing/reagents.dm +++ b/code/controllers/subsystem/processing/reagents.dm @@ -2,11 +2,11 @@ PROCESSING_SUBSYSTEM_DEF(reagents) name = "Reagents" - init_order = INIT_ORDER_REAGENTS priority = FIRE_PRIORITY_REAGENTS wait = 0.25 SECONDS //You might think that rate_up_lim has to be set to half, but since everything is normalised around seconds_per_tick, it automatically adjusts it to be per second. Magic! flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + init_stage = INITSTAGE_EARLY ///What time was it when we last ticked var/previous_world_time = 0 diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm index c58840cfa7a..45a10f3a974 100644 --- a/code/controllers/subsystem/processing/station.dm +++ b/code/controllers/subsystem/processing/station.dm @@ -1,6 +1,5 @@ PROCESSING_SUBSYSTEM_DEF(station) name = "Station" - init_order = INIT_ORDER_STATION flags = SS_BACKGROUND runlevels = RUNLEVEL_GAME wait = 5 SECONDS diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm index d149bc5e77c..fe733a1ccfa 100644 --- a/code/controllers/subsystem/profiler.dm +++ b/code/controllers/subsystem/profiler.dm @@ -1,6 +1,6 @@ SUBSYSTEM_DEF(profiler) name = "Profiler" - init_order = INIT_ORDER_PROFILER + init_stage = INITSTAGE_FIRST runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY wait = 300 SECONDS var/fetch_cost = 0 diff --git a/code/controllers/subsystem/queuelinks.dm b/code/controllers/subsystem/queuelinks.dm index 1f891ee3ea5..20b55622931 100644 --- a/code/controllers/subsystem/queuelinks.dm +++ b/code/controllers/subsystem/queuelinks.dm @@ -2,14 +2,10 @@ SUBSYSTEM_DEF(queuelinks) name = "Queue Links" - flags = SS_NO_FIRE - init_order = INIT_ORDER_QUEUELINKS + flags = SS_NO_FIRE | SS_NO_INIT ///assoc list of pending queues, id = /datum/queue_link var/list/queues = list() -/datum/controller/subsystem/queuelinks/Initialize() - return SS_INIT_SUCCESS - ///Creates or adds to a queue with the id supplied, if the queue is now or above the size of the queue, calls MatchedLinks and clears queue. /// queues with a size of 0 wait never pop until something is added with an actual queue_max /datum/controller/subsystem/queuelinks/proc/add_to_queue(atom/what, id, queue_max = 0) diff --git a/code/controllers/subsystem/radioactive_nebula.dm b/code/controllers/subsystem/radioactive_nebula.dm index 17c0cc9b3da..585514a7f0d 100644 --- a/code/controllers/subsystem/radioactive_nebula.dm +++ b/code/controllers/subsystem/radioactive_nebula.dm @@ -4,6 +4,9 @@ /// Controls making objects irradiated when Radioactive Nebula is in effect. SUBSYSTEM_DEF(radioactive_nebula) name = "Radioactive Nebula" + dependencies = list( + /datum/controller/subsystem/processing/station + ) flags = SS_BACKGROUND wait = 30 SECONDS diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm index 9979a1a7312..b06b6ff6f85 100644 --- a/code/controllers/subsystem/research.dm +++ b/code/controllers/subsystem/research.dm @@ -3,7 +3,9 @@ SUBSYSTEM_DEF(research) name = "Research" priority = FIRE_PRIORITY_RESEARCH wait = 10 - init_order = INIT_ORDER_RESEARCH + dependencies = list( + /datum/controller/subsystem/processing/station + ) //TECHWEB STATIC var/list/techweb_nodes = list() //associative id = node datum var/list/techweb_designs = list() //associative id = node datum diff --git a/code/controllers/subsystem/restaurant.dm b/code/controllers/subsystem/restaurant.dm index 7a795f72115..034a7610cb6 100644 --- a/code/controllers/subsystem/restaurant.dm +++ b/code/controllers/subsystem/restaurant.dm @@ -5,7 +5,6 @@ This subsystem exists to serve as a holder for important info for the restaurant SUBSYSTEM_DEF(restaurant) name = "Restaurant" wait = 20 SECONDS //Roll for new guests but don't do it too fast. - init_order = INIT_ORDER_RESTAURANT flags = SS_NO_FIRE ///All venues that exist, assoc list of type - reference var/list/all_venues = list() diff --git a/code/controllers/subsystem/security_level.dm b/code/controllers/subsystem/security_level.dm index cb61af0f3e0..8ad6da2847b 100644 --- a/code/controllers/subsystem/security_level.dm +++ b/code/controllers/subsystem/security_level.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(security_level) name = "Security Level" can_fire = FALSE // We will control when we fire in this subsystem - init_order = INIT_ORDER_SECURITY_LEVEL /// Currently set security level var/datum/security_level/current_security_level /// A list of initialised security level datums. diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index f011d01ca67..c4428f297ae 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -5,7 +5,6 @@ SUBSYSTEM_DEF(server_maint) wait = 6 flags = SS_POST_FIRE_TIMING priority = FIRE_PRIORITY_SERVER_MAINT - init_order = INIT_ORDER_SERVER_MAINT init_stage = INITSTAGE_EARLY runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/list/currentrun @@ -34,11 +33,11 @@ SUBSYSTEM_DEF(server_maint) "dead_mob_list" = GLOB.dead_mob_list, "keyloop_list" = GLOB.keyloop_list, //A null here will cause new clients to be unable to move. totally unacceptable ) - + var/datum/tgs_version/tgsversion = world.TgsVersion() if(tgsversion) SSblackbox.record_feedback("text", "server_tools", 1, tgsversion.raw_parameter) - + return SS_INIT_SUCCESS /datum/controller/subsystem/server_maint/fire(resumed = FALSE) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 060e50e4159..231e0f027e4 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -9,7 +9,11 @@ SUBSYSTEM_DEF(shuttle) name = "Shuttle" wait = 1 SECONDS - init_order = INIT_ORDER_SHUTTLE + dependencies = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms, + /datum/controller/subsystem/air + ) flags = SS_KEEP_TIMING runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME diff --git a/code/controllers/subsystem/skills.dm b/code/controllers/subsystem/skills.dm index fdf868cf1f7..0ece2ac2aaa 100644 --- a/code/controllers/subsystem/skills.dm +++ b/code/controllers/subsystem/skills.dm @@ -5,7 +5,6 @@ This subsystem mostly exists to populate and manage the skill singletons. SUBSYSTEM_DEF(skills) name = "Skills" flags = SS_NO_FIRE - init_order = INIT_ORDER_SKILLS ///Dictionary of skill.type || skill ref var/list/all_skills = list() ///List of level names with index corresponding to skill level diff --git a/code/controllers/subsystem/sounds.dm b/code/controllers/subsystem/sounds.dm index bcc06e67f63..5f4807d6cca 100644 --- a/code/controllers/subsystem/sounds.dm +++ b/code/controllers/subsystem/sounds.dm @@ -3,7 +3,7 @@ SUBSYSTEM_DEF(sounds) name = "Sounds" flags = SS_NO_FIRE - init_order = INIT_ORDER_SOUNDS + init_stage = INITSTAGE_EARLY var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels /// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up. var/static/random_channels_min = 50 diff --git a/code/controllers/subsystem/spatial_gridmap.dm b/code/controllers/subsystem/spatial_gridmap.dm index d906de2dc7b..e8c8df0171e 100644 --- a/code/controllers/subsystem/spatial_gridmap.dm +++ b/code/controllers/subsystem/spatial_gridmap.dm @@ -79,7 +79,9 @@ */ SUBSYSTEM_DEF(spatial_grid) can_fire = FALSE - init_order = INIT_ORDER_SPATIAL_GRID + dependencies = list( + /datum/controller/subsystem/mapping + ) name = "Spatial Grid" ///list of the spatial_grid_cell datums per z level, arranged in the order of y index then x index diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index d2912cb7fe1..44c5f54aa68 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -1,8 +1,6 @@ SUBSYSTEM_DEF(statpanels) name = "Stat Panels" wait = 4 - init_order = INIT_ORDER_STATPANELS - init_stage = INITSTAGE_EARLY priority = FIRE_PRIORITY_STATPANEL runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY flags = SS_NO_INIT diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm index 757df6a2266..8a955b2fb0d 100644 --- a/code/controllers/subsystem/stickyban.dm +++ b/code/controllers/subsystem/stickyban.dm @@ -1,6 +1,5 @@ SUBSYSTEM_DEF(stickyban) name = "PRISM" - init_order = INIT_ORDER_STICKY_BAN flags = SS_NO_FIRE var/list/cache = list() diff --git a/code/controllers/subsystem/stock_market.dm b/code/controllers/subsystem/stock_market.dm index 7d0e0ea9262..1cce5a8c549 100644 --- a/code/controllers/subsystem/stock_market.dm +++ b/code/controllers/subsystem/stock_market.dm @@ -2,7 +2,6 @@ SUBSYSTEM_DEF(stock_market) name = "Stock Market" wait = 60 SECONDS - init_order = INIT_ORDER_DEFAULT runlevels = RUNLEVEL_GAME /// Associated list of materials and their prices at the given time. diff --git a/code/controllers/subsystem/tcgsetup.dm b/code/controllers/subsystem/tcgsetup.dm index e52474adac5..5904c821e79 100644 --- a/code/controllers/subsystem/tcgsetup.dm +++ b/code/controllers/subsystem/tcgsetup.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(trading_card_game) name = "Trading Card Game" flags = SS_NO_FIRE - init_order = INIT_ORDER_TCG /// Base directory for all related string files var/card_directory = "strings/tcg" /// List of card files to load diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index e0c153749f2..a957ff9b2e4 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -3,8 +3,6 @@ SUBSYSTEM_DEF(ticker) name = "Ticker" - init_order = INIT_ORDER_TICKER - priority = FIRE_PRIORITY_TICKER flags = SS_KEEP_TIMING runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm index 4c706fdaf6d..57ff27a2737 100644 --- a/code/controllers/subsystem/time_track.dm +++ b/code/controllers/subsystem/time_track.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(time_track) name = "Time Tracking" wait = 100 - init_order = INIT_ORDER_TIMETRACK runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/time_dilation_current = 0 diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index c314fa7d38b..2b2d9393287 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -17,7 +17,6 @@ SUBSYSTEM_DEF(timer) name = "Timer" wait = 1 // SS_TICKER subsystem, so wait is in ticks - init_order = INIT_ORDER_TIMER priority = FIRE_PRIORITY_TIMER flags = SS_TICKER|SS_NO_INIT diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index 8df9349ff03..2d526e31353 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -1,9 +1,7 @@ SUBSYSTEM_DEF(title) name = "Title Screen" flags = SS_NO_FIRE - init_order = INIT_ORDER_TITLE init_stage = INITSTAGE_EARLY - var/file_path var/icon/icon var/icon/previous_icon diff --git a/code/controllers/subsystem/traitor.dm b/code/controllers/subsystem/traitor.dm index afa15e7606c..599fd91e578 100644 --- a/code/controllers/subsystem/traitor.dm +++ b/code/controllers/subsystem/traitor.dm @@ -1,5 +1,9 @@ SUBSYSTEM_DEF(traitor) name = "Traitor" + dependencies = list( + /datum/controller/subsystem/mapping, + /datum/controller/subsystem/atoms + ) flags = SS_KEEP_TIMING wait = 10 SECONDS runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME diff --git a/code/controllers/subsystem/tts.dm b/code/controllers/subsystem/tts.dm index 0fccd2eeefa..9d3f7d6b76f 100644 --- a/code/controllers/subsystem/tts.dm +++ b/code/controllers/subsystem/tts.dm @@ -2,7 +2,6 @@ SUBSYSTEM_DEF(tts) name = "Text To Speech" wait = 0.05 SECONDS priority = FIRE_PRIORITY_TTS - init_order = INIT_ORDER_TTS runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME /// Queued HTTP requests that have yet to be sent. TTS requests are handled as lists rather than datums. diff --git a/code/controllers/subsystem/unplanned_controllers.dm b/code/controllers/subsystem/unplanned_controllers.dm index 57b4ed68f16..e33e212c404 100644 --- a/code/controllers/subsystem/unplanned_controllers.dm +++ b/code/controllers/subsystem/unplanned_controllers.dm @@ -4,7 +4,9 @@ SUBSYSTEM_DEF(unplanned_controllers) name = "Unplanned AI Controllers" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_UNPLANNED_NPC - init_order = INIT_ORDER_AI_CONTROLLERS + dependencies = list( + /datum/controller/subsystem/movement/ai_movement + ) wait = 0.25 SECONDS runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME ///what ai status are we interested in diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index 1afe1c62100..717455a77bc 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -1,16 +1,12 @@ SUBSYSTEM_DEF(vis_overlays) name = "Vis contents overlays" wait = 1 MINUTES + flags = SS_NO_INIT priority = FIRE_PRIORITY_VIS - init_order = INIT_ORDER_VIS - var/list/vis_overlay_cache + var/list/vis_overlay_cache = list() var/list/currentrun -/datum/controller/subsystem/vis_overlays/Initialize() - vis_overlay_cache = list() - return SS_INIT_SUCCESS - /datum/controller/subsystem/vis_overlays/fire(resumed = FALSE) if(!resumed) currentrun = vis_overlay_cache.Copy() diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 84880a47948..5dd3f537bfc 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -5,7 +5,6 @@ SUBSYSTEM_DEF(vote) name = "Vote" wait = 1 SECONDS flags = SS_KEEP_TIMING - init_order = INIT_ORDER_VOTE runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT /// A list of all generated action buttons diff --git a/code/controllers/subsystem/wardrobe.dm b/code/controllers/subsystem/wardrobe.dm index ac435cc9a6d..d52752402ab 100644 --- a/code/controllers/subsystem/wardrobe.dm +++ b/code/controllers/subsystem/wardrobe.dm @@ -9,6 +9,10 @@ SUBSYSTEM_DEF(wardrobe) name = "Wardrobe" wait = 10 // This is more like a queue then anything else flags = SS_BACKGROUND + dependencies = list( + /datum/controller/subsystem/atoms, + /datum/controller/subsystem/mapping + ) runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT // We're going to fill up our cache while players sit in the lobby /// How much to cache outfit items /// Multiplier, 2 would mean cache enough items to stock 1 of each preloaded order twice, etc diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index b8496a623eb..516722c8d00 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -2,6 +2,9 @@ SUBSYSTEM_DEF(weather) name = "Weather" flags = SS_BACKGROUND + dependencies = list( + /datum/controller/subsystem/mapping + ) wait = 10 runlevels = RUNLEVEL_GAME var/list/processing = list() diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 98b2c87094e..fa09f840805 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -917,3 +917,41 @@ ADMIN_VERB(queue_tracy, R_DEBUG, "Toggle Tracy Next Round", "Toggle running the ADMIN_VERB_CUSTOM_EXIST_CHECK(queue_tracy) return CONFIG_GET(flag/allow_tracy_queue) && fexists(TRACY_DLL_PATH) #endif + +/datum/mc_dependency_ui + +/datum/mc_dependency_ui/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MCDependencyDebug") + ui.set_autoupdate(FALSE) + ui.open() + +/datum/mc_dependency_ui/ui_state(mob/user) + return ADMIN_STATE(R_DEBUG) + +/datum/mc_dependency_ui/ui_data(mob/user) + var/list/data = list() + + var/list/subsystems = Master.subsystems.Copy() + sortTim(subsystems, GLOBAL_PROC_REF(cmp_subsystem_init)) + + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + var/list/sub_data = list() + sub_data["name"] = subsystem.name + var/list/dependents = list() + for(var/datum/controller/subsystem/dependent as anything in subsystem.dependents) + dependents += dependent.name + sub_data["dependents"] = dependents + data += list(sub_data) + + return list( + "subsystems" = data + ) + +/datum/mc_dependency_ui/ui_assets(mob/user) + return list(get_asset_datum(/datum/asset/simple/plane_background)) + +ADMIN_VERB(debug_mc_dependencies, R_DEBUG, "Debug MC Dependencies", "Debug MC dependencies.", ADMIN_CATEGORY_DEBUG) + var/datum/mc_dependency_ui/data = new /datum/mc_dependency_ui() + data.ui_interact(usr) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 34b34369299..c1c81d711cb 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -89,7 +89,10 @@ return "/list ([list_value.len])" // if it's a number, is it a bitflag? - var/list/valid_bitflags = get_valid_bitflags(name) + var/list/valid_bitflags + if(!isnum(name)) + valid_bitflags = get_valid_bitflags(name) + if(!length(valid_bitflags)) return "[VV_HTML_ENCODE(value)]" diff --git a/tgui/packages/tgui/interfaces/MCDependencyDebug.tsx b/tgui/packages/tgui/interfaces/MCDependencyDebug.tsx new file mode 100644 index 00000000000..52c4b20fc07 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MCDependencyDebug.tsx @@ -0,0 +1,295 @@ +import { useLayoutEffect, useMemo, useRef, useState } from 'react'; +import { Box, InfinitePlane, Stack } from 'tgui-core/components'; +import { classes } from 'tgui-core/react'; + +import { resolveAsset } from '../assets'; +import { useBackend } from '../backend'; +import { Window } from '../layouts'; +import { Connection, Connections, ConnectionStyle } from './common/Connections'; +import { ABSOLUTE_Y_OFFSET } from './IntegratedCircuit/constants'; + +type Coord = { + x: number; + y: number; +}; + +type SubsystemData = { + name: string; + dependents: string[]; +}; + +type Subsystem = { + name: string; + dependents: Subsystem[]; +}; + +type DependencyData = { + subsystems: SubsystemData[]; +}; + +function getPosition(el: HTMLElement | null): Coord { + let xPos = 0; + let yPos = 0; + + while (el !== null) { + xPos += el.offsetLeft; + yPos += el.offsetTop; + el = el.offsetParent as HTMLElement | null; + } + + return { + x: xPos, + y: yPos + ABSOLUTE_Y_OFFSET, + }; +} + +type GraphNodeProps = { + name: string; + x: number; + y: number; + inputRef: (element: HTMLElement) => void; + outputRef: (element: HTMLElement) => void; +}; + +function GraphNode(props: GraphNodeProps) { + const { name, inputRef, outputRef, x, y } = props; + + return ( + + + + + + + + + + + + {name} + + + + + + + + + + + + + ); +} + +type SubsystemRef = { + input?: HTMLElement; + output?: HTMLElement; +}; + +type ConnectionRef = Record; + +type SubsystemCoord = { + input: Coord; + output: Coord; +}; + +type ConnectionData = Record; + +type SubsystemLayer = Record; + +type SubsystemMap = Record; + +function evaluateSubsystemLayer( + subsystem: Subsystem, + depth: number, + data: SubsystemLayer, +) { + data[subsystem.name] = Math.max(depth, data[subsystem.name] || 0); + for (let i = 0; i < subsystem.dependents.length; i++) { + evaluateSubsystemLayer(subsystem.dependents[i], depth + 1, data); + } +} + +export function MCDependencyDebug(props) { + const { data } = useBackend(); + const { subsystems } = data; + const connectionDom = useRef({}); + const [connectionData, setConnectionData] = useState({}); + + useLayoutEffect(() => { + const doms = connectionDom.current; + const newConnectionData: ConnectionData = {}; + for (let i = 0; i < subsystems.length; i++) { + const subsystem = subsystems[i]; + const domElements = doms[subsystem.name]; + if (domElements.input === undefined || domElements.output === undefined) { + continue; + } + newConnectionData[subsystem.name] = { + input: getPosition(domElements.input), + output: getPosition(domElements.output), + }; + } + setConnectionData(newConnectionData); + }, [subsystems]); + + const subsystemsLayered = useMemo(() => { + const namesToSubsystem: SubsystemMap = {}; + const subsystemsGraph: Subsystem[] = []; + + for (let i = 0; i < subsystems.length; i++) { + const subsystem = subsystems[i]; + const subsystemNode = { + name: subsystem.name, + dependents: [], + }; + namesToSubsystem[subsystem.name] = subsystemNode; + subsystemsGraph.push(subsystemNode); + } + + for (let i = 0; i < subsystems.length; i++) { + const subsystem = subsystems[i]; + subsystemsGraph[i].dependents = subsystem.dependents.map( + (val) => namesToSubsystem[val], + ); + } + + const subsystemLayer: SubsystemLayer = {}; + for (let i = 0; i < subsystemsGraph.length; i++) { + const subsystem = subsystemsGraph[i]; + evaluateSubsystemLayer(subsystem, 1, subsystemLayer); + } + return subsystemLayer; + }, [subsystems]); + + const connections: Connection[] = []; + for (let i = 0; i < subsystems.length; i++) { + const subsystem = subsystems[i]; + const from = connectionData[subsystem.name]; + if (from === undefined) { + continue; + } + for (let j = 0; j < subsystem.dependents.length; j++) { + const outputSubsystem = subsystem.dependents[j]; + const target = connectionData[outputSubsystem]; + if (target === undefined) { + continue; + } + + connections.push({ + from: from.output, + to: target.input, + style: ConnectionStyle.SUBWAY_SHARP, + index: i, + color: `hsl(${60 + 5 * (i % 30)}, 50%, ${50 + (i % 30)}%)`, + }); + } + } + + return ( + + + + + First + + {subsystems.map((subsystem, y) => ( + { + if (connectionDom.current[subsystem.name] === undefined) { + connectionDom.current[subsystem.name] = {}; + } + connectionDom.current[subsystem.name].input = element; + }} + outputRef={(element) => { + if (connectionDom.current[subsystem.name] === undefined) { + connectionDom.current[subsystem.name] = {}; + } + connectionDom.current[subsystem.name].output = element; + }} + /> + ))} + + Last + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/common/Connections.tsx b/tgui/packages/tgui/interfaces/common/Connections.tsx index 55e6e31895d..068da736082 100644 --- a/tgui/packages/tgui/interfaces/common/Connections.tsx +++ b/tgui/packages/tgui/interfaces/common/Connections.tsx @@ -4,9 +4,10 @@ import { CSS_COLORS } from '../../constants'; const SVG_CURVE_INTENSITY = 64; -enum ConnectionStyle { +export enum ConnectionStyle { CURVE = 'curve', SUBWAY = 'subway', + SUBWAY_SHARP = 'subway sharp', } export type Position = { @@ -25,6 +26,8 @@ export type Connection = { style?: ConnectionStyle; // Optional: the ref of what element this connection is sourced ref?: string; + // Optional: Used to group some connections together + index?: number; }; export const Connections = (props: { @@ -78,6 +81,17 @@ export const Connections = (props: { path += `L ${to.x} ${to.y}`; break; } + case ConnectionStyle.SUBWAY_SHARP: { + let offset = 16; + if (val.index !== undefined) { + offset = 8 * (val.index % 32) + 32; + } + const yDiff = Math.abs(to.y - from.y); + path += `L ${Math.max(from.x + offset, to.x - offset)} ${from.y}`; + path += `L ${Math.max(from.x + offset, to.x - offset)} ${to.y}`; + path += `L ${to.x} ${to.y}`; + break; + } } return ( @@ -85,6 +99,7 @@ export const Connections = (props: { className={classes([ isColorClass(val.color) && `color-stroke-${val.color}`, ])} + stroke={(!isColorClass(val.color) && val.color) || undefined} key={index} d={path} fill="transparent"