diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm index 74134e6ff2..eb5e89276e 100644 --- a/code/ATMOSPHERICS/datum_pipe_network.dm +++ b/code/ATMOSPHERICS/datum_pipe_network.dm @@ -20,7 +20,7 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS gases.Cut() // Do not qdel the gases, we don't own them return ..() - proc/process() + process() //Equalize gases amongst pipe if called for if(update) update = 0 @@ -75,7 +75,7 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS for(var/datum/pipeline/line_member in line_members) gases += line_member.air - + for(var/datum/gas_mixture/air in gases) volume += air.volume diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index 28391c4352..fc47bca938 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -20,7 +20,7 @@ datum/pipeline edges = null . = ..() - proc/process()//This use to be called called from the pipe networks + process()//This use to be called called from the pipe networks //Check to see if pressure is within acceptable limits var/pressure = air.return_pressure() diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm index ad03630666..2683922820 100644 --- a/code/__defines/MC.dm +++ b/code/__defines/MC.dm @@ -1,15 +1,81 @@ -#define MC_TICK_CHECK ( ( TICK_USAGE > GLOB.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 = GLOB.CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count +#define MC_TICK_CHECK ( ( TICK_USAGE > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 ) +#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){\ - GLOB.CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\ - --split_tick_phases;\ - } else {\ - GLOB.CURRENT_TICKLIMIT = original_tick_limit;\ - } + if(split_tick_phases > 1){\ + Master.current_ticklimit = ((original_tick_limit - TICK_USAGE) / split_tick_phases) + TICK_USAGE;\ + --split_tick_phases;\ + } else {\ + Master.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)) +#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current)) + +#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) +#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) + +#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} + +#define START_PROCESSING(Processor, Datum) if (!Datum.is_processing) {Datum.is_processing = TRUE;Processor.processing += Datum} +#define STOP_PROCESSING(Processor, Datum) Datum.is_processing = FALSE;Processor.processing -= Datum + +//! SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) + +/// subsystem does not initialize. +#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 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 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 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 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 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 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 64 + +//! SUBSYSTEM STATES +#define SS_IDLE 0 /// aint doing shit. +#define SS_QUEUED 1 /// queued to run +#define SS_RUNNING 2 /// actively running +#define SS_PAUSED 3 /// paused by mc_tick_check +#define SS_SLEEPING 4 /// fire() slept. +#define SS_PAUSING 5 /// in the middle of pausing + +#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\ +/datum/controller/subsystem/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/##X + +#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\ +/datum/controller/subsystem/processing/##X/New(){\ + NEW_SS_GLOBAL(SS##X);\ + PreInit();\ +}\ +/datum/controller/subsystem/processing/##X // Boilerplate code for multi-step processors. See machines.dm for example use. #define INTERNAL_PROCESS_STEP(this_step, initial_step, proc_to_call, cost_var, next_step)\ @@ -23,71 +89,3 @@ if(current_step == this_step || (initial_step && !resumed)) /* So we start at st resumed = 0;\ current_step = next_step;\ } - -// 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)) -#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current)) - -#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) -#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) - -#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} - -#define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum} -#define STOP_PROCESSING(Processor, Datum) Datum.isprocessing = 0;Processor.processing -= Datum - -//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier) - -//subsystem does not initialize. -#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 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 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 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 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 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 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 64 - -//SUBSYSTEM STATES -#define SS_IDLE 0 //aint doing shit. -#define SS_QUEUED 1 //queued to run -#define SS_RUNNING 2 //actively running -#define SS_PAUSED 3 //paused by mc_tick_check -#define SS_SLEEPING 4 //fire() slept. -#define SS_PAUSING 5 //in the middle of pausing - -// Standard way to define a global subsystem, keep boilerplate organized here! -#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\ -/datum/controller/subsystem/##X/New(){\ - NEW_SS_GLOBAL(SS##X);\ - PreInit();\ -}\ -/datum/controller/subsystem/##X - #define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\ -/datum/controller/subsystem/processing/##X/New(){\ - NEW_SS_GLOBAL(SS##X);\ - PreInit();\ -}\ -/datum/controller/subsystem/processing/##X \ No newline at end of file diff --git a/code/__defines/_lists.dm b/code/__defines/_lists.dm new file mode 100644 index 0000000000..f011662cec --- /dev/null +++ b/code/__defines/_lists.dm @@ -0,0 +1,54 @@ +// Helper macros to aid in optimizing lazy instantiation of lists. +// All of these are null-safe, you can use them without knowing if the list var is initialized yet + +//Picks from the list, with some safeties, and returns the "default" arg if it fails +#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default) +// Ensures L is initailized after this point +#define LAZYINITLIST(L) if (!L) L = list() +// Sets a L back to null iff it is empty +#define UNSETEMPTY(L) if (L && !length(L)) L = null +// Removes I from list L, and sets I to null if it is now empty +#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } } +// Adds I to L, initalizing I if necessary +#define LAZYADD(L, I) if(!L) { L = list(); } L += I; +#define LAZYOR(L, I) if(!L) { L = list(); } L |= I; +#define LAZYFIND(L, V) L ? L.Find(V) : 0 +// Reads I from L safely - Works with both associative and traditional lists. +#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null) +// Turns LAZYINITLIST(L) L[K] = V into ... for associated lists +#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V; +// Reads the length of L, returning 0 if null +#define LAZYLEN(L) length(L) +// Null-safe L.Cut() +#define LAZYCLEARLIST(L) if(L) L.Cut() +// 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()) + +// binary search sorted insert +// IN: Object to be inserted +// LIST: List to insert object into +// TYPECONT: The typepath of the contents of the list +// COMPARE: The variable on the objects to compare +#define BINARY_INSERT(IN, LIST, TYPECONT, COMPARE) \ + var/__BIN_CTTL = length(LIST);\ + if(!__BIN_CTTL) {\ + LIST += IN;\ + } else {\ + var/__BIN_LEFT = 1;\ + var/__BIN_RIGHT = __BIN_CTTL;\ + var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\ + var/##TYPECONT/__BIN_ITEM;\ + while(__BIN_LEFT < __BIN_RIGHT) {\ + __BIN_ITEM = LIST[__BIN_MID];\ + if(__BIN_ITEM.##COMPARE <= IN.##COMPARE) {\ + __BIN_LEFT = __BIN_MID + 1;\ + } else {\ + __BIN_RIGHT = __BIN_MID;\ + };\ + __BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\ + };\ + __BIN_ITEM = LIST[__BIN_MID];\ + __BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\ + LIST.Insert(__BIN_MID, IN);\ + } diff --git a/code/__defines/_tick.dm b/code/__defines/_tick.dm index 7ca3fb23a2..2c761b86f9 100644 --- a/code/__defines/_tick.dm +++ b/code/__defines/_tick.dm @@ -3,7 +3,7 @@ #define TICK_LIMIT_MC 70 #define TICK_LIMIT_MC_INIT_DEFAULT 98 -#define TICK_CHECK ( TICK_USAGE > GLOB.CURRENT_TICKLIMIT ) +#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit ) #define CHECK_TICK if TICK_CHECK stoplag() #define TICK_USAGE world.tick_usage diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm new file mode 100644 index 0000000000..5de8214191 --- /dev/null +++ b/code/__defines/flags.dm @@ -0,0 +1,6 @@ +#define ALL (~0) +#define NONE 0 + +// datum_flags +#define DF_VAR_EDITED (1<<0) +#define DF_ISPROCESSING (1<<1) diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm index 51c6db5325..ab85326658 100644 --- a/code/__defines/qdel.dm +++ b/code/__defines/qdel.dm @@ -22,7 +22,13 @@ #define QDELETED(X) (!X || X.gc_destroyed) #define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) +//Qdel helper macros. +#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE) +#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME) +#define QDEL_NULL(item) qdel(item); item = null +#define QDEL_LIST_NULL(x) if(x) { for(var/y in x) { qdel(y) } ; x = null } #define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); } +#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE) #define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); } #define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); } diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 94c233d752..2270f80d02 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -1,18 +1,23 @@ //Timing subsystem //Don't run if there is an identical unique timer active -#define TIMER_UNIQUE 0x1 +//if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer +#define TIMER_UNIQUE (1<<0) //For unique timers: Replace the old timer rather then not start this one -#define TIMER_OVERRIDE 0x2 +#define TIMER_OVERRIDE (1<<1) //Timing should be based on how timing progresses on clients, not the sever. // tracking this is more expensive, // should only be used in conjuction with things that have to progress client side, such as animate() or sound() -#define TIMER_CLIENT_TIME 0x4 +#define TIMER_CLIENT_TIME (1<<2) //Timer can be stopped using deltimer() -#define TIMER_STOPPABLE 0x8 +#define TIMER_STOPPABLE (1<<3) //To be used with TIMER_UNIQUE //prevents distinguishing identical timers with the wait variable -#define TIMER_NO_HASH_WAIT 0x10 -#define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something +#define TIMER_NO_HASH_WAIT (1<<4) +//Loops the timer repeatedly until qdeleted +//In most cases you want a subsystem instead +#define TIMER_LOOP (1<<5) + +#define TIMER_ID_NULL -1 #define INITIALIZATION_INSSATOMS 0 //New should not call Initialize #define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE) @@ -47,18 +52,19 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G // 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_DECALS 16 -#define INIT_ORDER_ATOMS 15 -#define INIT_ORDER_MACHINES 10 -#define INIT_ORDER_SHUTTLES 3 -#define INIT_ORDER_DEFAULT 0 -#define INIT_ORDER_LIGHTING 0 -#define INIT_ORDER_AIR -1 -#define INIT_ORDER_PLANETS -4 -#define INIT_ORDER_HOLOMAPS -5 -#define INIT_ORDER_OVERLAY -6 -#define INIT_ORDER_XENOARCH -20 -#define INIT_ORDER_CIRCUIT -21 +#define INIT_ORDER_DECALS 16 +#define INIT_ORDER_ATOMS 15 +#define INIT_ORDER_MACHINES 10 +#define INIT_ORDER_SHUTTLES 3 +#define INIT_ORDER_TIMER 1 +#define INIT_ORDER_DEFAULT 0 +#define INIT_ORDER_LIGHTING 0 +#define INIT_ORDER_AIR -1 +#define INIT_ORDER_PLANETS -4 +#define INIT_ORDER_HOLOMAPS -5 +#define INIT_ORDER_OVERLAY -6 +#define INIT_ORDER_XENOARCH -20 +#define INIT_ORDER_CIRCUIT -21 // Subsystem fire priority, from lowest to highest priority @@ -68,6 +74,8 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_AIRFLOW 30 #define FIRE_PRIORITY_AIR 35 +#define FIRE_PRIORITY_OBJ 40 +#define FIRE_PRIORITY_PROCESS 45 #define FIRE_PRIORITY_DEFAULT 50 #define FIRE_PRIORITY_PLANETS 75 #define FIRE_PRIORITY_MACHINES 100 diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index b9e5dd8623..855aa9c138 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -250,7 +250,7 @@ proc/listclearnulls(list/list) else L[key] = temp[key] - + //Mergesort: divides up the list into halves to begin the sort /proc/sortKey(var/list/client/L, var/order = 1) if(isnull(L) || L.len < 2) diff --git a/code/_helpers/sorts/comparators.dm b/code/_helpers/sorts/comparators.dm index 7fd07ec711..2e3411a220 100644 --- a/code/_helpers/sorts/comparators.dm +++ b/code/_helpers/sorts/comparators.dm @@ -42,3 +42,6 @@ . = B[STAT_ENTRY_TIME] - A[STAT_ENTRY_TIME] if (!.) . = B[STAT_ENTRY_COUNT] - A[STAT_ENTRY_COUNT] + +/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b) + return a.timeToRun - b.timeToRun diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index ce640731a6..fa916bdb85 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -140,7 +140,7 @@ var/round_start_time = 0 . += CEILING(i*DELTA_CALC, 1) sleep(i*world.tick_lag*DELTA_CALC) i *= 2 - while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, GLOB.CURRENT_TICKLIMIT)) + while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit)) #undef DELTA_CALC diff --git a/code/_macros.dm b/code/_macros.dm index 9cd11a6c15..1c6a918d1d 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -65,32 +65,4 @@ #define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE) -#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) } ; x = null } - -#define QDEL_NULL(x) if(x) { qdel(x) ; x = null } - #define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") } - -// Helper macros to aid in optimizing lazy instantiation of lists. -// All of these are null-safe, you can use them without knowing if the list var is initialized yet - -//Picks from the list, with some safeties, and returns the "default" arg if it fails -#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default) -// Ensures L is initailized after this point -#define LAZYINITLIST(L) if (!L) L = list() -// Sets a L back to null iff it is empty -#define UNSETEMPTY(L) if (L && !L.len) L = null -// Removes I from list L, and sets I to null if it is now empty -#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } -// Adds I to L, initalizing I if necessary -#define LAZYADD(L, I) if(!L) { L = list(); } L += I; -// Reads I from L safely - Works with both associative and traditional lists. -#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) -// Reads the length of L, returning 0 if null -#define LAZYLEN(L) length(L) -// Null-safe L.Cut() -#define LAZYCLEARLIST(L) if(L) L.Cut() -// 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() ) -// Turns LAZYINITLIST(L) L[K] = V into ... for associated lists -#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V; \ No newline at end of file diff --git a/code/controllers/ProcessScheduler/core/process.dm b/code/controllers/ProcessScheduler/core/process.dm index 2965a52abe..6bbcb62a54 100644 --- a/code/controllers/ProcessScheduler/core/process.dm +++ b/code/controllers/ProcessScheduler/core/process.dm @@ -155,7 +155,7 @@ /datum/controller/process/proc/setup() -/datum/controller/process/proc/process() +/datum/controller/process/process() started() doWork() finished() diff --git a/code/controllers/ProcessScheduler/core/processScheduler.dm b/code/controllers/ProcessScheduler/core/processScheduler.dm index 86dcdac287..c5b658de15 100644 --- a/code/controllers/ProcessScheduler/core/processScheduler.dm +++ b/code/controllers/ProcessScheduler/core/processScheduler.dm @@ -70,7 +70,7 @@ var/global/datum/controller/processScheduler/processScheduler spawn(0) process() -/datum/controller/processScheduler/proc/process() +/datum/controller/processScheduler/process() while(isRunning) checkRunningProcesses() queueProcesses() diff --git a/code/controllers/Processes/obj.dm b/code/controllers/Processes/obj.dm deleted file mode 100644 index 6032cbb541..0000000000 --- a/code/controllers/Processes/obj.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/controller/process/obj/setup() - name = "obj" - schedule_interval = 20 // every 2 seconds - start_delay = 8 - -/datum/controller/process/obj/started() - ..() - if(!processing_objects) - processing_objects = list() - -/datum/controller/process/obj/doWork() - for(last_object in processing_objects) - var/datum/O = last_object - if(!QDELETED(O)) - try - O:process() - catch(var/exception/e) - catchException(e, O) - SCHECK - else - catchBadType(O) - processing_objects -= O - -/datum/controller/process/obj/statProcess() - ..() - stat(null, "[processing_objects.len] objects") \ No newline at end of file diff --git a/code/controllers/Processes/supply.dm b/code/controllers/Processes/supply.dm index 139f0923d1..aec0d624c7 100644 --- a/code/controllers/Processes/supply.dm +++ b/code/controllers/Processes/supply.dm @@ -66,7 +66,7 @@ var/datum/controller/supply/supply_controller = new() // Supply shuttle ticker - handles supply point regeneration // This is called by the process scheduler every thirty seconds -/datum/controller/supply/proc/process() +/datum/controller/supply/process() points += points_per_process //To stop things being sent to CentCom which should not be sent to centcomm. Recursively checks for these types. diff --git a/code/controllers/autotransfer.dm b/code/controllers/autotransfer.dm index afd1435ffa..c9bc4ac2c0 100644 --- a/code/controllers/autotransfer.dm +++ b/code/controllers/autotransfer.dm @@ -10,7 +10,7 @@ datum/controller/transfer_controller/New() datum/controller/transfer_controller/Destroy() processing_objects -= src -datum/controller/transfer_controller/proc/process() +datum/controller/transfer_controller/process() currenttick = currenttick + 1 if (round_duration_in_ticks >= timerbuffer - 1 MINUTE) vote.autotransfer() diff --git a/code/controllers/emergency_shuttle_controller.dm b/code/controllers/emergency_shuttle_controller.dm index 05468bee76..bcc7187a3c 100644 --- a/code/controllers/emergency_shuttle_controller.dm +++ b/code/controllers/emergency_shuttle_controller.dm @@ -26,7 +26,7 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle escape_pods = list() ..() -/datum/emergency_shuttle_controller/proc/process() +/datum/emergency_shuttle_controller/process() if (wait_for_launch) if (evac && auto_recall && world.time >= auto_recall_time) recall() diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 050251fb0d..0b292e45c4 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -13,14 +13,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new //THIS IS THE INIT ORDER //Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe //GOT IT MEMORIZED? -GLOBAL_VAR_INIT(MC_restart_clear, 0) -GLOBAL_VAR_INIT(MC_restart_timeout, 0) -GLOBAL_VAR_INIT(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 -GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) - /datum/controller/master name = "Master" @@ -62,6 +54,10 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) var/static/restart_timeout = 0 var/static/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/static/current_ticklimit + /datum/controller/master/New() // Highlander-style: there can only be one! Kill off the old and replace it with the new. var/list/_subsystems = list() @@ -98,14 +94,14 @@ GLOBAL_VAR_INIT(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 < GLOB.MC_restart_timeout) + if (world.time < Master.restart_timeout) return 0 - if (world.time < GLOB.MC_restart_clear) - GLOB.MC_restart_count *= 0.5 + if (world.time < Master.restart_clear) + Master.restart_count *= 0.5 - var/delay = 50 * ++GLOB.MC_restart_count - GLOB.MC_restart_timeout = world.time + delay - GLOB.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 = FALSE //stop ticking this one try new/datum/controller/master() @@ -176,13 +172,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) var/start_timeofday = REALTIMEOFDAY // Initialize subsystems. - GLOB.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 - GLOB.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"]!" @@ -291,7 +287,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag))) var/starting_tick_usage = TICK_USAGE if (processing <= 0) - GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue @@ -300,7 +296,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) // (because sleeps are processed in the order received, longer sleeps are more likely to run first) if (starting_tick_usage > TICK_LIMIT_MC) //if there isn't enough time to bother doing anything this tick, sleep a bit. sleep_delta *= 2 - GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5 + current_ticklimit = TICK_LIMIT_RUNNING * 0.5 sleep(world.tick_lag * (processing * sleep_delta)) continue @@ -346,7 +342,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) if (!error_level) iteration++ error_level++ - GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue @@ -358,7 +354,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) if (!error_level) iteration++ error_level++ - GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING sleep(10) continue error_level-- @@ -369,9 +365,9 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) iteration++ last_run = world.time src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta) - GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + current_ticklimit = TICK_LIMIT_RUNNING if (processing * sleep_delta <= world.tick_lag) - GLOB.CURRENT_TICKLIMIT -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick + current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick sleep(world.tick_lag * (processing * sleep_delta)) @@ -463,7 +459,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) // Reduce tick allocation for subsystems that overran on their last tick. tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun) - GLOB.CURRENT_TICKLIMIT = round(TICK_USAGE + tick_precentage) + current_ticklimit = round(TICK_USAGE + tick_precentage) if (!(queue_node_flags & SS_TICKER)) ran_non_ticker = TRUE diff --git a/code/controllers/subsystems/processing/fastprocess.dm b/code/controllers/subsystems/processing/fastprocess.dm new file mode 100644 index 0000000000..9622e02146 --- /dev/null +++ b/code/controllers/subsystems/processing/fastprocess.dm @@ -0,0 +1,6 @@ +//Fires five times every second. + +PROCESSING_SUBSYSTEM_DEF(fastprocess) + name = "Fast Processing" + wait = 2 + stat_tag = "FP" diff --git a/code/controllers/subsystems/processing/obj.dm b/code/controllers/subsystems/processing/obj.dm new file mode 100644 index 0000000000..26021fb267 --- /dev/null +++ b/code/controllers/subsystems/processing/obj.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(obj) + name = "Objects" + priority = FIRE_PRIORITY_OBJ + flags = SS_NO_INIT + wait = 20 diff --git a/code/controllers/subsystems/processing/processing.dm b/code/controllers/subsystems/processing/processing.dm new file mode 100644 index 0000000000..c5d6dfa126 --- /dev/null +++ b/code/controllers/subsystems/processing/processing.dm @@ -0,0 +1,35 @@ +//Used to process objects. Fires once every second. + +SUBSYSTEM_DEF(processing) + name = "Processing" + priority = FIRE_PRIORITY_PROCESS + flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT + wait = 10 + + var/stat_tag = "P" //Used for logging + var/list/processing = list() + var/list/currentrun = list() + +/datum/controller/subsystem/processing/stat_entry() + ..("[stat_tag]:[processing.len]") + +/datum/controller/subsystem/processing/fire(resumed = 0) + if (!resumed) + currentrun = processing.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = currentrun + + while(current_run.len) + var/datum/thing = current_run[current_run.len] + current_run.len-- + if(QDELETED(thing)) + processing -= thing + else if(thing.process(wait) == PROCESS_KILL) + // fully stop so that a future START_PROCESSING will work + STOP_PROCESSING(src, thing) + if (MC_TICK_CHECK) + return + +/datum/proc/process() + set waitfor = 0 + return PROCESS_KILL diff --git a/code/controllers/subsystems/time_track.dm b/code/controllers/subsystems/time_track.dm new file mode 100644 index 0000000000..aed175ed27 --- /dev/null +++ b/code/controllers/subsystems/time_track.dm @@ -0,0 +1,37 @@ +SUBSYSTEM_DEF(time_track) + name = "Time Tracking" + wait = 600 + flags = SS_NO_INIT|SS_NO_TICK_CHECK + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + + var/time_dilation_current = 0 + + var/time_dilation_avg_fast = 0 + var/time_dilation_avg = 0 + var/time_dilation_avg_slow = 0 + + var/first_run = TRUE + + var/last_tick_realtime = 0 + var/last_tick_byond_time = 0 + var/last_tick_tickcount = 0 + +/datum/controller/subsystem/time_track/fire() + + var/current_realtime = REALTIMEOFDAY + var/current_byondtime = world.time + var/current_tickcount = world.time/world.tick_lag + + if (!first_run) + var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag)) + + time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100 + + time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current) + time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast) + time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg) + else + first_run = FALSE + last_tick_realtime = current_realtime + last_tick_byond_time = current_byondtime + last_tick_tickcount = current_tickcount diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm new file mode 100644 index 0000000000..e2d9ec6913 --- /dev/null +++ b/code/controllers/subsystems/timer.dm @@ -0,0 +1,522 @@ +#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth) +#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN)||BUCKET_LEN) +#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1))) +#define TIMER_ID_MAX (2**24) //max float with integer precision + +SUBSYSTEM_DEF(timer) + name = "Timer" + wait = 1 //SS_TICKER subsystem, so wait is in ticks + init_order = INIT_ORDER_TIMER + + flags = SS_TICKER|SS_NO_INIT + + var/list/datum/timedevent/second_queue = list() //awe, yes, you've had first queue, but what about second queue? + var/list/hashes = list() + + var/head_offset = 0 //world.time of the first entry in the the bucket. + var/practical_offset = 1 //index of the first non-empty item in the bucket. + var/bucket_resolution = 0 //world.tick_lag the bucket was designed for + var/bucket_count = 0 //how many timers are in the buckets + + var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick. + + var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup) + + var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time" + + var/last_invoke_tick = 0 + var/static/last_invoke_warning = 0 + var/static/bucket_auto_reset = TRUE + +/datum/controller/subsystem/timer/PreInit() + bucket_list.len = BUCKET_LEN + head_offset = world.time + bucket_resolution = world.tick_lag + +/datum/controller/subsystem/timer/stat_entry(msg) + ..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]") + +/datum/controller/subsystem/timer/fire(resumed = FALSE) + var/lit = last_invoke_tick + var/last_check = world.time - TICKS2DS(BUCKET_LEN*1.5) + var/list/bucket_list = src.bucket_list + + if(!bucket_count) + last_invoke_tick = world.time + + if(lit && lit < last_check && head_offset < last_check && last_invoke_warning < last_check) + last_invoke_warning = world.time + var/msg = "No regular timers processed in the last [BUCKET_LEN*1.5] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!" + message_admins(msg) + WARNING(msg) + if(bucket_auto_reset) + bucket_resolution = 0 + + log_world("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + for (var/i in 1 to length(bucket_list)) + var/datum/timedevent/bucket_head = bucket_list[i] + if (!bucket_head) + continue + + log_world("Active timers at index [i]:") + + var/datum/timedevent/bucket_node = bucket_head + var/anti_loop_check = 1000 + do + log_world(get_timer_debug_string(bucket_node)) + bucket_node = bucket_node.next + anti_loop_check-- + while(bucket_node && bucket_node != bucket_head && anti_loop_check) + log_world("Active timers in the second_queue queue:") + for(var/I in second_queue) + log_world(get_timer_debug_string(I)) + + var/cut_start_index = 1 + var/next_clienttime_timer_index = 0 + var/len = length(clienttime_timers) + + for (next_clienttime_timer_index in 1 to len) + if (MC_TICK_CHECK) + next_clienttime_timer_index-- + break + var/datum/timedevent/ctime_timer = clienttime_timers[next_clienttime_timer_index] + if (ctime_timer.timeToRun > REALTIMEOFDAY) + next_clienttime_timer_index-- + break + + var/datum/callback/callBack = ctime_timer.callBack + if (!callBack) + clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1) + CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]") + + ctime_timer.spent = REALTIMEOFDAY + callBack.InvokeAsync() + + if(ctime_timer.flags & TIMER_LOOP) + ctime_timer.spent = 0 + clienttime_timers.Insert(ctime_timer, 1) + cut_start_index++ + else + qdel(ctime_timer) + + + if (next_clienttime_timer_index) + clienttime_timers.Cut(cut_start_index,next_clienttime_timer_index+1) + + if (MC_TICK_CHECK) + return + + var/static/list/spent = list() + var/static/datum/timedevent/timer + if (practical_offset > BUCKET_LEN) + head_offset += TICKS2DS(BUCKET_LEN) + practical_offset = 1 + resumed = FALSE + + if ((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution)) + reset_buckets() + bucket_list = src.bucket_list + resumed = FALSE + + + if (!resumed) + timer = null + + while (practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time) + var/datum/timedevent/head = bucket_list[practical_offset] + if (!timer || !head || timer == head) + head = bucket_list[practical_offset] + timer = head + while (timer) + var/datum/callback/callBack = timer.callBack + if (!callBack) + bucket_resolution = null //force bucket recreation + CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + + if (!timer.spent) + spent += timer + timer.spent = world.time + callBack.InvokeAsync() + last_invoke_tick = world.time + + if (MC_TICK_CHECK) + return + + timer = timer.next + if (timer == head) + break + + + bucket_list[practical_offset++] = null + + //we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket. + var/i = 0 + var/L = length(second_queue) + for (i in 1 to L) + timer = second_queue[i] + if (timer.timeToRun >= TIMER_MAX) + i-- + break + + if (timer.timeToRun < head_offset) + bucket_resolution = null //force bucket recreation + CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + + if (timer.callBack && !timer.spent) + timer.callBack.InvokeAsync() + spent += timer + bucket_count++ + else if(!QDELETED(timer)) + qdel(timer) + continue + + if (timer.timeToRun < head_offset + TICKS2DS(practical_offset)) + bucket_resolution = null //force bucket recreation + CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + if (timer.callBack && !timer.spent) + timer.callBack.InvokeAsync() + spent += timer + bucket_count++ + else if(!QDELETED(timer)) + qdel(timer) + continue + + bucket_count++ + var/bucket_pos = max(1, BUCKET_POS(timer)) + + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] + if (!bucket_head) + bucket_list[bucket_pos] = timer + timer.next = null + timer.prev = null + continue + + if (!bucket_head.prev) + bucket_head.prev = bucket_head + timer.next = bucket_head + timer.prev = bucket_head.prev + timer.next.prev = timer + timer.prev.next = timer + if (i) + second_queue.Cut(1, i+1) + + timer = null + + bucket_count -= length(spent) + + for (var/i in spent) + var/datum/timedevent/qtimer = i + if(QDELETED(qtimer)) + bucket_count++ + continue + if(!(qtimer.flags & TIMER_LOOP)) + qdel(qtimer) + else + bucket_count++ + qtimer.spent = 0 + qtimer.bucketEject() + if(qtimer.flags & TIMER_CLIENT_TIME) + qtimer.timeToRun = REALTIMEOFDAY + qtimer.wait + else + qtimer.timeToRun = world.time + qtimer.wait + qtimer.bucketJoin() + + spent.len = 0 + +//formated this way to be runtime resistant +/datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE) + . = "Timer: [TE]" + . += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]" + if(TE.spent) + . += ", SPENT([TE.spent])" + if(QDELETED(TE)) + . += ", QDELETED" + if(!TE.callBack) + . += ", NO CALLBACK" + +/datum/controller/subsystem/timer/proc/reset_buckets() + var/list/bucket_list = src.bucket_list + var/list/alltimers = list() + //collect the timers currently in the bucket + for (var/bucket_head in bucket_list) + if (!bucket_head) + continue + var/datum/timedevent/bucket_node = bucket_head + do + alltimers += bucket_node + bucket_node = bucket_node.next + while(bucket_node && bucket_node != bucket_head) + + bucket_list.len = 0 + bucket_list.len = BUCKET_LEN + + practical_offset = 1 + bucket_count = 0 + head_offset = world.time + bucket_resolution = world.tick_lag + + alltimers += second_queue + if (!length(alltimers)) + return + + sortTim(alltimers, .proc/cmp_timer) + + var/datum/timedevent/head = alltimers[1] + + if (head.timeToRun < head_offset) + head_offset = head.timeToRun + + var/new_bucket_count + var/i = 1 + for (i in 1 to length(alltimers)) + var/datum/timedevent/timer = alltimers[1] + if (!timer) + continue + + var/bucket_pos = BUCKET_POS(timer) + if (timer.timeToRun >= TIMER_MAX) + i-- + break + + + if (!timer.callBack || timer.spent) + WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]") + if (timer.callBack) + qdel(timer) + continue + + new_bucket_count++ + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] + if (!bucket_head) + bucket_list[bucket_pos] = timer + timer.next = null + timer.prev = null + continue + + if (!bucket_head.prev) + bucket_head.prev = bucket_head + timer.next = bucket_head + timer.prev = bucket_head.prev + timer.next.prev = timer + timer.prev.next = timer + if (i) + alltimers.Cut(1, i+1) + second_queue = alltimers + bucket_count = new_bucket_count + + +/datum/controller/subsystem/timer/Recover() + second_queue |= SStimer.second_queue + hashes |= SStimer.hashes + timer_id_dict |= SStimer.timer_id_dict + bucket_list |= SStimer.bucket_list + +/datum/timedevent + var/id + var/datum/callback/callBack + var/timeToRun + var/wait + var/hash + var/list/flags + var/spent = 0 //time we ran the timer. + var/name //for easy debugging. + //cicular doublely linked list + var/datum/timedevent/next + var/datum/timedevent/prev + +/datum/timedevent/New(datum/callback/callBack, wait, flags, hash) + var/static/nextid = 1 + id = TIMER_ID_NULL + src.callBack = callBack + src.wait = wait + src.flags = flags + src.hash = hash + + if (flags & TIMER_CLIENT_TIME) + timeToRun = REALTIMEOFDAY + wait + else + timeToRun = world.time + wait + + if (flags & TIMER_UNIQUE) + SStimer.hashes[hash] = src + + if (flags & TIMER_STOPPABLE) + id = num2text(nextid, 100) + if (nextid >= SHORT_REAL_LIMIT) + nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT)) + else + nextid++ + SStimer.timer_id_dict[id] = src + + name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])" + + if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME)) + CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]") + + if (callBack.object != GLOBAL_PROC && !QDESTROYING(callBack.object)) + LAZYADD(callBack.object.active_timers, src) + + bucketJoin() + +/datum/timedevent/Destroy() + ..() + if (flags & TIMER_UNIQUE && hash) + SStimer.hashes -= hash + + if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers) + callBack.object.active_timers -= src + UNSETEMPTY(callBack.object.active_timers) + + callBack = null + + if (flags & TIMER_STOPPABLE) + SStimer.timer_id_dict -= id + + if (flags & TIMER_CLIENT_TIME) + if (!spent) + spent = world.time + SStimer.clienttime_timers -= src + return QDEL_HINT_IWILLGC + + if (!spent) + spent = world.time + bucketEject() + else + if (prev && prev.next == src) + prev.next = next + if (next && next.prev == src) + next.prev = prev + next = null + prev = null + return QDEL_HINT_IWILLGC + +/datum/timedevent/proc/bucketEject() + var/bucketpos = BUCKET_POS(src) + var/list/bucket_list = SStimer.bucket_list + var/list/second_queue = SStimer.second_queue + var/datum/timedevent/buckethead + if(bucketpos > 0) + buckethead = bucket_list[bucketpos] + if(buckethead == src) + bucket_list[bucketpos] = next + SStimer.bucket_count-- + else if(timeToRun < TIMER_MAX || next || prev) + SStimer.bucket_count-- + else + var/l = length(second_queue) + second_queue -= src + if(l == length(second_queue)) + SStimer.bucket_count-- + if(prev != next) + prev.next = next + next.prev = prev + else + prev?.next = null + next?.prev = null + prev = next = null + +/datum/timedevent/proc/bucketJoin() + var/list/L + + if (flags & TIMER_CLIENT_TIME) + L = SStimer.clienttime_timers + else if (timeToRun >= TIMER_MAX) + L = SStimer.second_queue + + if(L) + BINARY_INSERT(src, L, datum/timedevent, timeToRun) + return + + //get the list of buckets + var/list/bucket_list = SStimer.bucket_list + + //calculate our place in the bucket list + var/bucket_pos = BUCKET_POS(src) + + //get the bucket for our tick + var/datum/timedevent/bucket_head = bucket_list[bucket_pos] + SStimer.bucket_count++ + //empty bucket, we will just add ourselves + if (!bucket_head) + bucket_list[bucket_pos] = src + return + //other wise, lets do a simplified linked list add. + if (!bucket_head.prev) + bucket_head.prev = bucket_head + next = bucket_head + prev = bucket_head.prev + next.prev = src + prev.next = src + +/datum/timedevent/proc/getcallingtype() + . = "ERROR" + if (callBack.object == GLOBAL_PROC) + . = "GLOBAL_PROC" + else + . = "[callBack.object.type]" + +/proc/addtimer(datum/callback/callback, wait = 0, flags = 0) + if (!callback) + CRASH("addtimer called without a callback") + + if (wait < 0) + crash_with("addtimer called with a negative wait. Converting to [world.tick_lag]") + + if (callback.object != GLOBAL_PROC && QDELETED(callback.object) && !QDESTROYING(callback.object)) + crash_with("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not be supported and may refuse to run or run with a 0 wait") + + wait = max(CEILING(wait, world.tick_lag), world.tick_lag) + + if(wait >= INFINITY) + CRASH("Attempted to create timer with INFINITY delay") + + var/hash + + if (flags & TIMER_UNIQUE) + var/list/hashlist + if(flags & TIMER_NO_HASH_WAIT) + hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, flags & TIMER_CLIENT_TIME) + else + hashlist = list(callback.object, "(\ref[callback.object])", callback.delegate, wait, flags & TIMER_CLIENT_TIME) + hashlist += callback.arguments + hash = hashlist.Join("|||||||") + + var/datum/timedevent/hash_timer = SStimer.hashes[hash] + if(hash_timer) + if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist. + hash_timer.hash = null //but keep it from accidentally deleting us + else + if (flags & TIMER_OVERRIDE) + hash_timer.hash = null //no need having it delete it's hash if we are going to replace it + qdel(hash_timer) + else + if (hash_timer.flags & TIMER_STOPPABLE) + . = hash_timer.id + return + else if(flags & TIMER_OVERRIDE) + crash_with("TIMER_OVERRIDE used without TIMER_UNIQUE") + + var/datum/timedevent/timer = new(callback, wait, flags, hash) + return timer.id + +/proc/deltimer(id) + if (!id) + return FALSE + if (id == TIMER_ID_NULL) + CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag") + if (!istext(id)) + if (istype(id, /datum/timedevent)) + qdel(id) + return TRUE + //id is string + var/datum/timedevent/timer = SStimer.timer_id_dict[id] + if (timer && !timer.spent) + qdel(timer) + return TRUE + return FALSE + + +#undef BUCKET_LEN +#undef BUCKET_POS +#undef TIMER_MAX +#undef TIMER_ID_MAX diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index ba1bb23c33..9a4d9bad46 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -32,7 +32,7 @@ var/global/list/round_voters = list() // Keeps track of the individuals voting f // Tell qdel() to Del() this object. return QDEL_HINT_HARDDEL_NOW -/datum/controller/vote/proc/process() //called by master_controller +/datum/controller/vote/process() //called by master_controller if(mode) // No more change mode votes after the game has started. if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index fd58220657..36d430a0ed 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -5,8 +5,9 @@ /datum var/gc_destroyed //Time when this object was destroyed. + var/list/active_timers //for SStimer var/weakref/weakref // Holder of weakref instance pointing to this datum - var/is_processing = FALSE // If this datum is in an MC processing list, this will be set to its name. + var/is_processing //If is processing, may or may not have the name of the list it's in. #ifdef TESTING var/tmp/running_find_references @@ -17,6 +18,16 @@ // This should be overridden to remove all references pointing to the object being destroyed. // Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE. /datum/proc/Destroy(force=FALSE) + + //clear timers + var/list/timers = active_timers + active_timers = null + for(var/thing in timers) + var/datum/timedevent/timer = thing + if (timer.spent) + continue + qdel(timer) + weakref = null // Clear this reference to ensure it's kept for as brief duration as possible. tag = null GLOB.nanomanager.close_uis(src) diff --git a/code/datums/helper_datums/global_iterator.dm b/code/datums/helper_datums/global_iterator.dm index d511b5d233..2ebab5582d 100644 --- a/code/datums/helper_datums/global_iterator.dm +++ b/code/datums/helper_datums/global_iterator.dm @@ -1,3 +1,7 @@ +/* + DO NOT USE THIS. THIS IS BEING DEPRECATED BY PROCESSING SUBSYSTEMS (controllers/subsystems/processing) AND TIMERS. +*/ + /* README: @@ -109,9 +113,6 @@ Data storage vars: CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.") return 1 - proc/process() - return - proc/active() return control_switch diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index ecafc0dbc5..578c1a0d8c 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -13,7 +13,7 @@ ///process() ///Called by the gameticker -/datum/game_mode/proc/process() +/datum/game_mode/process() // Slow this down a bit so latejoiners have a chance of being antags. process_count++ if(process_count >= 10) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 15113de8ab..f3a01f9dcf 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -43,10 +43,10 @@ var/global/datum/controller/gameticker/ticker 'sound/music/title2.ogg',\ 'sound/music/clouds.s3m',\ 'sound/music/space_oddity.ogg') //Ground Control to Major Tom, this song is cool, what's going on? - + send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]") - - do + + do pregame_timeleft = 180 to_chat(world, "Welcome to the pregame lobby!") to_chat(world, "Please set up your character and select ready. The round will start in [pregame_timeleft] seconds.") @@ -90,7 +90,7 @@ var/global/datum/controller/gameticker/ticker src.mode = gamemode_cache[pickweight(weighted_modes)] else src.mode = config.pick_mode(master_mode) - + if(!src.mode) current_state = GAME_STATE_PREGAME Master.SetRunLevel(RUNLEVEL_LOBBY) @@ -309,7 +309,7 @@ var/global/datum/controller/gameticker/ticker to_chat(M, "Colony Directorship not forced on anyone.") - proc/process() + process() if(current_state != GAME_STATE_PLAYING) return 0 diff --git a/code/game/gamemodes/malfunction/malf_research.dm b/code/game/gamemodes/malfunction/malf_research.dm index da7a4df668..58f7d56c13 100644 --- a/code/game/gamemodes/malfunction/malf_research.dm +++ b/code/game/gamemodes/malfunction/malf_research.dm @@ -43,7 +43,7 @@ // Proc: process() // Parameters: None // Description: Processes CPU gain and research progress based on "realtime" calculation. -/datum/malf_research/proc/process(var/idle = 0) +/datum/malf_research/process(var/idle = 0) if(idle) // No power or running on APU. Do nothing. last_tick = world.time return diff --git a/code/game/gamemodes/malfunction/malf_research_ability.dm b/code/game/gamemodes/malfunction/malf_research_ability.dm index c6916208bd..8002dcead8 100644 --- a/code/game/gamemodes/malfunction/malf_research_ability.dm +++ b/code/game/gamemodes/malfunction/malf_research_ability.dm @@ -7,7 +7,7 @@ var/datum/malf_research_ability/next = null // Next research (if applicable). -/datum/malf_research_ability/proc/process(var/time = 0) +/datum/malf_research_ability/process(var/time = 0) invested += time if(invested >= price) unlocked = 1 \ No newline at end of file diff --git a/code/game/machinery/computer3/program.dm b/code/game/machinery/computer3/program.dm index b39998bdfd..bf84c1622e 100644 --- a/code/game/machinery/computer3/program.dm +++ b/code/game/machinery/computer3/program.dm @@ -117,7 +117,7 @@ Programs are a file that can be executed /* The computer object will transfer process() calls to the program. */ -/datum/file/program/proc/process() +/datum/file/program/process() if(refresh && computer && !computer.stat) computer.updateDialog() update_icon() diff --git a/code/game/machinery/embedded_controller/embedded_program_base.dm b/code/game/machinery/embedded_controller/embedded_program_base.dm index f579aca6f7..a8be295ccd 100644 --- a/code/game/machinery/embedded_controller/embedded_program_base.dm +++ b/code/game/machinery/embedded_controller/embedded_program_base.dm @@ -17,7 +17,7 @@ /datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param) return -/datum/computer/file/embedded_program/proc/process() +/datum/computer/file/embedded_program/process() return /datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index c103f1f39e..e5dcee8237 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -115,6 +115,8 @@ Class Procs: var/interact_offline = 0 // Can the machine be interacted with while de-powered. var/obj/item/weapon/circuitboard/circuit = null + var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess. + /obj/machinery/New(l, d=0) ..(l) if(d) @@ -125,10 +127,16 @@ Class Procs: /obj/machinery/initialize() . = ..() global.machines += src - START_MACHINE_PROCESSING(src) + if(!speed_process) + START_MACHINE_PROCESSING(src) + else + START_PROCESSING(SSfastprocess, src) /obj/machinery/Destroy() - STOP_MACHINE_PROCESSING(src) + if(!speed_process) + STOP_MACHINE_PROCESSING(src) + else + STOP_PROCESSING(SSfastprocess, src) global.machines -= src if(component_parts) for(var/atom/A in component_parts) @@ -151,8 +159,6 @@ Class Procs: if(!(use_power || idle_power_usage || active_power_usage)) return PROCESS_KILL - return - /obj/machinery/emp_act(severity) if(use_power && stat == 0) use_power(7500/severity) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index e92268f4da..7f90b97790 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -105,7 +105,7 @@ steam.start() -- spawns the effect /obj/effect/effect/sparks/initialize() . = ..() - schedule_task_in(5 SECONDS, /proc/qdel, list(src)) + QDEL_IN(src, 5 SECONDS) /obj/effect/effect/sparks/Destroy() var/turf/T = src.loc diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 919f8cb016..2e95441efe 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -144,7 +144,7 @@ if(!status) return lit = !lit if(lit) - processing_objects.Add(src) + START_PROCESSING(SSobj, src) if(href_list["amount"]) throw_amount = throw_amount + text2num(href_list["amount"]) throw_amount = max(50, min(5000, throw_amount)) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 442e6c3f1d..c5c8075c63 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -21,7 +21,7 @@ Destroy() QDEL_NULL(detonator) - QDEL_NULL_LIST(beakers) + QDEL_LIST_NULL(beakers) return ..() attack_self(mob/user as mob) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 9c2fb60434..29cdaf2cd6 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -58,10 +58,6 @@ /obj/item/proc/is_used_on(obj/O, mob/user) -/obj/proc/process() - processing_objects.Remove(src) - return 0 - /obj/assume_air(datum/gas_mixture/giver) if(loc) return loc.assume_air(giver) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 724799ebde..6cc424ad75 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -279,9 +279,6 @@ var/const/enterloopsanity = 100 L.Add(t) return L -/turf/proc/process() - return PROCESS_KILL - /turf/proc/contains_dense_objects() if(density) return 1 diff --git a/code/global.dm b/code/global.dm index 154eb3ea9c..ec87ef20e4 100644 --- a/code/global.dm +++ b/code/global.dm @@ -8,7 +8,6 @@ var/global/datum/datacore/data_core = null var/global/list/all_areas = list() var/global/list/machines = list() // ALL Machines, wether processing or not. var/global/list/processing_machines = list() // TODO - Move into SSmachines -var/global/list/processing_objects = list() var/global/list/processing_power_items = list() // TODO - Move into SSmachines var/global/list/active_diseases = list() var/global/list/hud_icon_reference = list() diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm index 26ffdade04..f8d853ca8c 100644 --- a/code/modules/alarm/alarm.dm +++ b/code/modules/alarm/alarm.dm @@ -31,7 +31,7 @@ cameras() // Sets up both cameras and last alarm area. set_source_data(source, duration, severity, hidden) -/datum/alarm/proc/process() +/datum/alarm/process() // Has origin gone missing? if(!origin && !end_time) end_time = world.time + ALARM_RESET_DELAY diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm index a07ca8bd3b..d7a7cdf713 100644 --- a/code/modules/alarm/alarm_handler.dm +++ b/code/modules/alarm/alarm_handler.dm @@ -7,7 +7,7 @@ var/list/datum/alarm/alarms_assoc = new // Associative list of alarms, to efficiently acquire them based on origin. var/list/listeners = new // A list of all objects interested in alarm changes. -/datum/alarm_handler/proc/process() +/datum/alarm_handler/process() for(var/datum/alarm/A in alarms) A.process() check_alarm_cleared(A) diff --git a/code/modules/busy_space/air_traffic.dm b/code/modules/busy_space/air_traffic.dm index bac3a0ab90..b3ac435cb1 100644 --- a/code/modules/busy_space/air_traffic.dm +++ b/code/modules/busy_space/air_traffic.dm @@ -17,7 +17,7 @@ var/datum/lore/atc_controller/atc = new/datum/lore/atc_controller next_message = world.time + rand(delay_min,delay_max) process() -/datum/lore/atc_controller/proc/process() +/datum/lore/atc_controller/process() if(world.time >= next_message) if(squelched) next_message = world.time + backoff_delay diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm index 4912b238c8..5311cb28b4 100644 --- a/code/modules/events/event.dm +++ b/code/modules/events/event.dm @@ -94,7 +94,7 @@ //Do not override this proc, instead use the appropiate procs. //This proc will handle the calls to the appropiate procs. -/datum/event/proc/process() +/datum/event/process() if(activeFor > startWhen && activeFor < endWhen) tick() diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 578c28e20f..cc5dfb44d4 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -21,7 +21,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT var/last_world_time = 0 -/datum/event_container/proc/process() +/datum/event_container/process() if(!next_event_time) set_event_delay() diff --git a/code/modules/events/event_manager.dm b/code/modules/events/event_manager.dm index 534c5aa56d..e4c728f1df 100644 --- a/code/modules/events/event_manager.dm +++ b/code/modules/events/event_manager.dm @@ -23,7 +23,7 @@ /datum/event_manager/New() allEvents = typesof(/datum/event) - /datum/event -/datum/event_manager/proc/process() +/datum/event_manager/process() for(var/datum/event/E in event_manager.active_events) E.process() diff --git a/code/modules/gamemaster/game_master.dm b/code/modules/gamemaster/game_master.dm index c435e868f6..16a6a03887 100644 --- a/code/modules/gamemaster/game_master.dm +++ b/code/modules/gamemaster/game_master.dm @@ -22,7 +22,7 @@ for(var/datum/gm_action/action in available_actions) action.gm = src -/datum/game_master/proc/process() +/datum/game_master/process() if(ticker && ticker.current_state == GAME_STATE_PLAYING && !suspended) adjust_staleness(1) adjust_danger(-1) diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm index b0aaab0a7c..27e6347e5a 100644 --- a/code/modules/hydroponics/seed_controller.dm +++ b/code/modules/hydroponics/seed_controller.dm @@ -131,7 +131,7 @@ var/global/datum/controller/plants/plant_controller // Set in New(). seed.set_trait(TRAIT_HIGHKPA_TOLERANCE,200) return seed -/datum/controller/plants/proc/process() +/datum/controller/plants/process() processing = 1 spawn(0) set background = 1 diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm index e1cb3a16c3..2ba47421a4 100644 --- a/code/modules/mob/mob_planes.dm +++ b/code/modules/mob/mob_planes.dm @@ -44,7 +44,7 @@ /datum/plane_holder/Destroy() my_mob = null - QDEL_NULL_LIST(plane_masters) //Goodbye my children, be free + QDEL_LIST_NULL(plane_masters) //Goodbye my children, be free return ..() /datum/plane_holder/proc/set_vis(var/which = null, var/state = FALSE) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index bada05e300..4e4dd6af5b 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -502,7 +502,7 @@ nanoui is used to open and update nano browser uis * * @return nothing */ -/datum/nanoui/proc/process(update = 0) +/datum/nanoui/process(update = 0) if (!src_object || !user) close() return diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm index 0364056b69..587b2b5bcd 100644 --- a/code/modules/planet/planet.dm +++ b/code/modules/planet/planet.dm @@ -45,7 +45,7 @@ )) update_sun() -/datum/planet/proc/process(last_fire) +/datum/planet/process(last_fire) if(current_time) var/difference = world.time - last_fire current_time = current_time.add_seconds((difference / 10) * PLANET_TIME_MODIFIER) diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm index a13cb87cc7..1cdbd47bd8 100644 --- a/code/modules/planet/weather.dm +++ b/code/modules/planet/weather.dm @@ -40,7 +40,7 @@ our_planet.update_sun() log_debug("[our_planet.name]'s weather is now [new_weather], with a temperature of [temperature]°K ([temperature - T0C]°C | [temperature * 1.8 - 459.67]°F).") -/datum/weather_holder/proc/process() +/datum/weather_holder/process() if(world.time >= next_weather_shift) if(!current_weather) // Roundstart (hopefully). initialize_weather() diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 1c38a2aa57..2117ca9ae3 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -96,7 +96,7 @@ return progress -/datum/chemical_reaction/proc/process(var/datum/reagents/holder) +/datum/chemical_reaction/process(var/datum/reagents/holder) //determine how far the reaction can proceed var/list/reaction_limits = list() for(var/reactant in required_reagents) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index d70e6e563d..402dc5a821 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -1,3 +1,7 @@ +#define OFF 0 +#define FORWARDS 1 +#define BACKWARDS 2 + //conveyor2 is pretty much like the original, except it supports corners, but not diverters. //note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards. @@ -10,7 +14,7 @@ layer = ABOVE_TURF_LAYER anchored = 1 circuit = /obj/item/weapon/circuitboard/conveyor - var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off + var/operating = OFF // 1 if running forward, -1 if backwards, 0 if off var/operable = 1 // true if can operate (no broken segments in this belt run) var/forwards // this is the default (forward) direction, set by the map dir var/backwards // hopefully self-explanatory @@ -36,7 +40,7 @@ backwards = turn(dir, 180) if(on) - operating = 1 + operating = FORWARDS setmove() component_parts = list() @@ -48,22 +52,23 @@ RefreshParts() /obj/machinery/conveyor/proc/setmove() - if(operating == 1) + if(operating == FORWARDS) movedir = forwards - else if(operating == -1) + else if(operating == BACKWARDS) movedir = backwards - else operating = 0 + else + operating = OFF update() /obj/machinery/conveyor/proc/update() if(stat & BROKEN) icon_state = "conveyor-broken" - operating = 0 + operating = OFF return if(!operable) - operating = 0 + operating = OFF if(stat & NOPOWER) - operating = 0 + operating = OFF icon_state = "conveyor[operating]" // machine process diff --git a/code/modules/shieldgen/shield_gen.dm b/code/modules/shieldgen/shield_gen.dm index de6d535a05..6983f71c1b 100644 --- a/code/modules/shieldgen/shield_gen.dm +++ b/code/modules/shieldgen/shield_gen.dm @@ -42,7 +42,7 @@ return ..() /obj/machinery/shield_gen/Destroy() - QDEL_NULL_LIST(field) + QDEL_LIST_NULL(field) return ..() /obj/machinery/shield_gen/emag_act(var/remaining_charges, var/mob/user) diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index ed90e66c6a..a6a02fd6a3 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -37,7 +37,7 @@ supply_controller.shuttle = null . = ..() -/datum/shuttle/proc/process() +/datum/shuttle/process() return /datum/shuttle/proc/init_docking_controllers() diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm index afd9bfdfa3..4aa0aa1918 100644 --- a/code/modules/spells/spell_code.dm +++ b/code/modules/spells/spell_code.dm @@ -64,7 +64,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now //still_recharging_msg = "[name] is still recharging." charge_counter = charge_max -/spell/proc/process() +/spell/process() spawn while(charge_counter < charge_max) charge_counter++ sleep(1) diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 1b03157e83..3f7fb158aa 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -87,7 +87,7 @@ Notes: /datum/tooltip/proc/hide() if (queueHide) - schedule_task_with_source_in(1, src, .proc/do_hide) + addtimer(CALLBACK(src, .proc/do_hide), 1) else do_hide() diff --git a/code/modules/xenoarcheaology/effect.dm b/code/modules/xenoarcheaology/effect.dm index 7a922f1149..2a41f7b707 100644 --- a/code/modules/xenoarcheaology/effect.dm +++ b/code/modules/xenoarcheaology/effect.dm @@ -60,7 +60,7 @@ /datum/artifact_effect/proc/DoEffectPulse(var/atom/holder) /datum/artifact_effect/proc/UpdateMove() -/datum/artifact_effect/proc/process() +/datum/artifact_effect/process() if(chargelevel < chargelevelmax) chargelevel++ diff --git a/code/modules/xenoarcheaology/finds/talking.dm b/code/modules/xenoarcheaology/finds/talking.dm index 72ff1330de..c6f7cff5ea 100644 --- a/code/modules/xenoarcheaology/finds/talking.dm +++ b/code/modules/xenoarcheaology/finds/talking.dm @@ -15,7 +15,7 @@ if(holder_atom) processing_objects.Add(src) -/datum/talking_atom/proc/process() +/datum/talking_atom/process() if(!holder_atom) processing_objects.Remove(src) diff --git a/polaris.dme b/polaris.dme index ad5ace8eb8..9fd19e7a5a 100644 --- a/polaris.dme +++ b/polaris.dme @@ -20,6 +20,7 @@ #include "code\world.dm" #include "code\__datastructures\globals.dm" #include "code\__defines\_compile_options.dm" +#include "code\__defines\_lists.dm" #include "code\__defines\_planes+layers.dm" #include "code\__defines\_tick.dm" #include "code\__defines\admin.dm" @@ -31,6 +32,7 @@ #include "code\__defines\construction.dm" #include "code\__defines\damage_organs.dm" #include "code\__defines\dna.dm" +#include "code\__defines\flags.dm" #include "code\__defines\gamemode.dm" #include "code\__defines\holomap.dm" #include "code\__defines\integrated_circuits.dm" @@ -181,9 +183,7 @@ #include "code\controllers\Processes\inactivity.dm" #include "code\controllers\Processes\mob.dm" #include "code\controllers\Processes\nanoui.dm" -#include "code\controllers\Processes\obj.dm" #include "code\controllers\Processes\radiation.dm" -#include "code\controllers\Processes\scheduler.dm" #include "code\controllers\Processes\sun.dm" #include "code\controllers\Processes\supply.dm" #include "code\controllers\Processes\ticker.dm" @@ -203,7 +203,12 @@ #include "code\controllers\subsystems\overlays.dm" #include "code\controllers\subsystems\planets.dm" #include "code\controllers\subsystems\shuttles.dm" +#include "code\controllers\subsystems\time_track.dm" +#include "code\controllers\subsystems\timer.dm" #include "code\controllers\subsystems\xenoarch.dm" +#include "code\controllers\subsystems\processing\fastprocess.dm" +#include "code\controllers\subsystems\processing\obj.dm" +#include "code\controllers\subsystems\processing\processing.dm" #include "code\datums\ai_law_sets.dm" #include "code\datums\ai_laws.dm" #include "code\datums\beam.dm" @@ -257,7 +262,6 @@ #include "code\datums\observation\logged_in.dm" #include "code\datums\observation\moved.dm" #include "code\datums\observation\observation.dm" -#include "code\datums\observation\task_triggered.dm" #include "code\datums\observation\turf_changed.dm" #include "code\datums\observation\unequipped.dm" #include "code\datums\observation\~cleanup.dm"