[MIRROR] Makes timer subsystems available as a new subsystem type (#5719)

* Makes timer subsystems available as a new subsystem type (#59073)

* Makes timer subsystems available as a new subsystem type

Co-authored-by: Emmett Gaines <ninjanomnom@gmail.com>
This commit is contained in:
SkyratBot
2021-05-15 20:52:50 +02:00
committed by GitHub
parent 3d4b251e47
commit 6c54894872
6 changed files with 53 additions and 33 deletions

View File

@@ -66,6 +66,13 @@
}\
/datum/controller/subsystem/##X
#define TIMER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/timer/##X);\
/datum/controller/subsystem/timer/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
/datum/controller/subsystem/timer/##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);\

View File

@@ -189,6 +189,7 @@
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_EXPLOSIONS 666
#define FIRE_PRIORITY_TIMER 700
#define FIRE_PRIORITY_SOUND_LOOPS 800
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.

View File

@@ -0,0 +1,3 @@
TIMER_SUBSYSTEM_DEF(sound_loops)
name = "Sound Loops"
priority = FIRE_PRIORITY_SOUND_LOOPS

View File

@@ -1,9 +1,9 @@
/// Controls how many buckets should be kept, each representing a tick. (1 minutes worth)
#define BUCKET_LEN (world.fps*1*60)
/// Helper for getting the correct bucket for a given timer
#define BUCKET_POS(timer) (((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN)
#define BUCKET_POS(timer) (((round((timer.timeToRun - timer.timer_subsystem.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN)
/// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue
#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
#define TIMER_MAX(timer_ss) (world.time + TICKS2DS(min(BUCKET_LEN-(timer_ss.practical_offset-DS2TICKS(world.time - timer_ss.head_offset))-1, BUCKET_LEN-1)))
/// Max float with integer precision
#define TIMER_ID_MAX (2**24)
@@ -43,6 +43,8 @@ SUBSYSTEM_DEF(timer)
var/list/clienttime_timers = list()
/// Contains the last time that a timer's callback was invoked, or the last tick the SS fired if no timers are being processed
var/last_invoke_tick = 0
/// Keeps track of the next index to work on for client timers
var/next_clienttime_timer_index = 0
/// Contains the last time that a warning was issued for not invoking callbacks
var/static/last_invoke_warning = 0
/// Boolean operator controlling if the timer SS will automatically reset buckets if it fails to invoke callbacks for an extended period of time
@@ -100,7 +102,6 @@ SUBSYSTEM_DEF(timer)
log_world(to_log.Join("\n"))
// Process client-time timers
var/static/next_clienttime_timer_index = 0
if (next_clienttime_timer_index)
clienttime_timers.Cut(1, next_clienttime_timer_index+1)
next_clienttime_timer_index = 0
@@ -181,7 +182,7 @@ SUBSYSTEM_DEF(timer)
var/i = 0
for (i in 1 to length(second_queue))
timer = second_queue[i]
if (timer.timeToRun >= TIMER_MAX)
if (timer.timeToRun >= TIMER_MAX(src))
i--
break
@@ -275,7 +276,7 @@ SUBSYSTEM_DEF(timer)
continue
// Check that the TTR is within the range covered by buckets, when exceeded we've finished
if (timer.timeToRun >= TIMER_MAX)
if (timer.timeToRun >= TIMER_MAX(src))
i--
break
@@ -348,8 +349,10 @@ SUBSYSTEM_DEF(timer)
var/datum/timedevent/next
/// Previous timed event in the bucket
var/datum/timedevent/prev
/// The timer subsystem this event is associated with
var/datum/controller/subsystem/timer/timer_subsystem
/datum/timedevent/New(datum/callback/callBack, wait, flags, hash, source)
/datum/timedevent/New(datum/callback/callBack, wait, flags, datum/controller/subsystem/timer/timer_subsystem, hash, source)
var/static/nextid = 1
id = TIMER_ID_NULL
src.callBack = callBack
@@ -357,13 +360,14 @@ SUBSYSTEM_DEF(timer)
src.flags = flags
src.hash = hash
src.source = source
src.timer_subsystem = timer_subsystem || SStimer
// Determine time at which the timer's callback should be invoked
timeToRun = (flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time) + wait
// Include the timer in the hash table if the timer is unique
if (flags & TIMER_UNIQUE)
SStimer.hashes[hash] = src
timer_subsystem.hashes[hash] = src
// Generate ID for the timer if the timer is stoppable, include in the timer id dictionary
if (flags & TIMER_STOPPABLE)
@@ -372,9 +376,9 @@ SUBSYSTEM_DEF(timer)
nextid += min(1, 2 ** round(nextid / SHORT_REAL_LIMIT))
else
nextid++
SStimer.timer_id_dict[id] = src
timer_subsystem.timer_id_dict[id] = src
if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
if ((timeToRun < world.time || timeToRun < timer_subsystem.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))
@@ -385,7 +389,7 @@ SUBSYSTEM_DEF(timer)
/datum/timedevent/Destroy()
..()
if (flags & TIMER_UNIQUE && hash)
SStimer.hashes -= hash
timer_subsystem.hashes -= hash
if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers)
callBack.object.active_timers -= src
@@ -394,12 +398,12 @@ SUBSYSTEM_DEF(timer)
callBack = null
if (flags & TIMER_STOPPABLE)
SStimer.timer_id_dict -= id
timer_subsystem.timer_id_dict -= id
if (flags & TIMER_CLIENT_TIME)
if (!spent)
spent = world.time
SStimer.clienttime_timers -= src
timer_subsystem.clienttime_timers -= src
return QDEL_HINT_IWILLGC
if (!spent)
@@ -423,8 +427,8 @@ SUBSYSTEM_DEF(timer)
// Store local references for the bucket list and secondary queue
// This is faster than referencing them from the datum itself
var/list/bucket_list = SStimer.bucket_list
var/list/second_queue = SStimer.second_queue
var/list/bucket_list = timer_subsystem.bucket_list
var/list/second_queue = timer_subsystem.second_queue
// Attempt to get the head of the bucket
var/datum/timedevent/buckethead
@@ -436,14 +440,14 @@ SUBSYSTEM_DEF(timer)
// into an existing bucket, or is otherwise not present in the secondary queue
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX)
SStimer.bucket_count--
timer_subsystem.bucket_count--
else if(timeToRun < TIMER_MAX(timer_subsystem))
timer_subsystem.bucket_count--
else
var/l = length(second_queue)
second_queue -= src
if(l == length(second_queue))
SStimer.bucket_count--
timer_subsystem.bucket_count--
// Remove the timed event from the bucket, ensuring to maintain
// the integrity of the bucket's list if relevant
@@ -473,20 +477,20 @@ SUBSYSTEM_DEF(timer)
// Check if this timed event should be diverted to the client time bucket, or the secondary queue
var/list/L
if (flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if (timeToRun >= TIMER_MAX)
L = SStimer.second_queue
L = timer_subsystem.clienttime_timers
else if (timeToRun >= TIMER_MAX(timer_subsystem))
L = timer_subsystem.second_queue
if(L)
BINARY_INSERT(src, L, /datum/timedevent, src, timeToRun, COMPARE_KEY)
return
// Get a local reference to the bucket list, this is faster than referencing the datum
var/list/bucket_list = SStimer.bucket_list
var/list/bucket_list = timer_subsystem.bucket_list
// Find the correct bucket for this timed event
var/bucket_pos = BUCKET_POS(src)
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
timer_subsystem.bucket_count++
// If there is no timed event at this position, then the bucket is 'empty'
// and we can just set this event to that position
@@ -522,7 +526,7 @@ SUBSYSTEM_DEF(timer)
* * wait deciseconds to run the timer for
* * flags flags for this timer, see: code\__DEFINES\subsystems.dm
*/
/proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, file, line)
/proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, datum/controller/subsystem/timer/timer_subsystem, file, line)
if (!callback)
CRASH("addtimer called without a callback")
@@ -538,6 +542,8 @@ SUBSYSTEM_DEF(timer)
if(wait >= INFINITY)
CRASH("Attempted to create timer with INFINITY delay")
timer_subsystem = timer_subsystem || SStimer
// Generate hash if relevant for timed events with the TIMER_UNIQUE flag
var/hash
if (flags & TIMER_UNIQUE)
@@ -547,7 +553,7 @@ SUBSYSTEM_DEF(timer)
hashlist += callback.arguments
hash = hashlist.Join("|||||||")
var/datum/timedevent/hash_timer = SStimer.hashes[hash]
var/datum/timedevent/hash_timer = timer_subsystem.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
@@ -562,7 +568,7 @@ SUBSYSTEM_DEF(timer)
else if(flags & TIMER_OVERRIDE)
stack_trace("TIMER_OVERRIDE used without TIMER_UNIQUE")
var/datum/timedevent/timer = new(callback, wait, flags, hash, file && "[file]:[line]")
var/datum/timedevent/timer = new(callback, wait, flags, timer_subsystem, hash, file && "[file]:[line]")
return timer.id
/**
@@ -571,7 +577,7 @@ SUBSYSTEM_DEF(timer)
* Arguments:
* * id a timerid or a /datum/timedevent
*/
/proc/deltimer(id)
/proc/deltimer(id, datum/controller/subsystem/timer/timer_subsystem)
if (!id)
return FALSE
if (id == TIMER_ID_NULL)
@@ -579,8 +585,9 @@ SUBSYSTEM_DEF(timer)
if (istype(id, /datum/timedevent))
qdel(id)
return TRUE
timer_subsystem = timer_subsystem || SStimer
//id is string
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id]
if (timer && (!timer.spent || timer.flags & TIMER_DELETE_ME))
qdel(timer)
return TRUE
@@ -592,7 +599,7 @@ SUBSYSTEM_DEF(timer)
* Arguments:
* * id a timerid or a /datum/timedevent
*/
/proc/timeleft(id)
/proc/timeleft(id, datum/controller/subsystem/timer/timer_subsystem)
if (!id)
return null
if (id == TIMER_ID_NULL)
@@ -600,8 +607,9 @@ SUBSYSTEM_DEF(timer)
if (istype(id, /datum/timedevent))
var/datum/timedevent/timer = id
return timer.timeToRun - world.time
timer_subsystem = timer_subsystem || SStimer
//id is string
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id]
return (timer && !timer.spent) ? timer.timeToRun - world.time : null
#undef BUCKET_LEN

View File

@@ -64,7 +64,7 @@
if(!timerid)
return
on_stop()
deltimer(timerid)
deltimer(timerid, SStimer)
timerid = null
/datum/looping_sound/proc/sound_loop(starttime)
@@ -74,7 +74,7 @@
if(!chance || prob(chance))
play(get_sound(starttime))
if(!timerid)
timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP)
timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP, SSsound_loops)
/datum/looping_sound/proc/play(soundfile, volume_override)
var/list/atoms_cache = output_atoms
@@ -99,7 +99,7 @@
if(start_sound)
play(start_sound, start_volume)
start_wait = start_length
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME)
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME, SSsound_loops)
/datum/looping_sound/proc/on_stop()
if(end_sound)

View File

@@ -381,6 +381,7 @@
#include "code\controllers\subsystem\server_maint.dm"
#include "code\controllers\subsystem\shuttle.dm"
#include "code\controllers\subsystem\skills.dm"
#include "code\controllers\subsystem\sound_loops.dm"
#include "code\controllers\subsystem\sounds.dm"
#include "code\controllers\subsystem\spacedrift.dm"
#include "code\controllers\subsystem\statpanel.dm"