Files
fulpstation/code/controllers/master_controller.dm
MrStonedOne 08b9f6c8c6 More Dynamic wait tweaks.
I forgot a step in the algo and made it so it was decreasing in its slowdown effect with more lag, not increasing.

I've also made the -1.5 magic number in the algo configurable. its was a simple buffer of cost the subsystem is allowed to use that isn't counted against it in dwait.
2015-07-10 23:25:34 -07:00

152 lines
5.0 KiB
Plaintext

//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one.
//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs)
//Update: all core-systems are now placed inside subsystem datums. This makes them highly configurable and easy to work with.
var/global/datum/controller/game_controller/master_controller = new()
/datum/controller/game_controller
var/processing_interval = 1 //The minimum length of time between MC ticks (in deciseconds). The highest this can be without affecting schedules, is the GCD of all subsystem var/wait. Set to 0 to disable all processing.
var/iteration = 0
var/cost = 0
var/SSCostPerSecond = 0
var/last_thing_processed
var/list/subsystems = list()
/datum/controller/game_controller/New()
//There can be only one master_controller. Out with the old and in with the new.
if(master_controller != src)
if(istype(master_controller))
Recover()
master_controller.Del()
else
init_subtypes(/datum/subsystem, subsystems)
master_controller = src
calculateGCD()
/*
calculate the longest number of ticks the MC can wait between each cycle without causing subsystems to not fire on schedule
*/
/datum/controller/game_controller/proc/calculateGCD()
var/GCD
for(var/datum/subsystem/SS in subsystems)
if(SS.wait)
GCD = Gcd(round(SS.wait*10), GCD)
GCD = round(GCD)
if(GCD < world.tick_lag*10)
GCD = world.tick_lag*10
processing_interval = GCD/10
/datum/controller/game_controller/proc/setup(zlevel)
if (zlevel && zlevel > 0 && zlevel <= world.maxz)
for(var/datum/subsystem/S in subsystems)
S.Initialize(world.timeofday, zlevel)
sleep(-1)
return
world << "<span class='boldannounce'>Initializing Subsystems...</span>"
//sort subsystems by priority, so they initialize in the correct order
sortTim(subsystems, /proc/cmp_subsystem_priority)
createRandomZlevel() //gate system
setup_map_transitions()
for(var/i=0, i<max_secret_rooms, i++)
make_mining_asteroid_secret()
//Eventually all this other setup stuff should be contained in subsystems and done in subsystem.Initialize()
for(var/datum/subsystem/S in subsystems)
S.Initialize(world.timeofday, zlevel)
sleep(-1)
for(var/datum/subsystem/S in subsystems)
S.AfterInitialize(zlevel)
world << "<span class='boldannounce'>Initializations complete</span>"
world.log << "Initializations complete"
world.sleep_offline = 1
world.fps = config.fps
sleep(-1)
process()
//used for smoothing out the cost values so they don't fluctuate wildly
#define MC_AVERAGE(average, current) (0.8*(average) + 0.2*(current))
/datum/controller/game_controller/process()
if(!Failsafe) new /datum/controller/failsafe()
spawn(0)
var/timer = world.time
for(var/datum/subsystem/SS in subsystems)
timer += processing_interval
SS.next_fire = timer
var/start_time
while(1) //far more efficient than recursively calling ourself
if(processing_interval > 0)
++iteration
start_time = world.timeofday
var/SubSystemRan = 0
for(var/datum/subsystem/SS in subsystems)
if(SS.can_fire > 0)
if(SS.next_fire <= world.time)
SubSystemRan = 1
timer = world.timeofday
last_thing_processed = SS.type
SS.last_fire = world.time
SS.fire()
SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer)
if (SS.dynamic_wait)
var/oldwait = SS.wait
var/GlobalCostDelta = (SSCostPerSecond-(SS.cost/(SS.wait/10)))-1
var/NewWait = MC_AVERAGE(oldwait,(SS.cost-SS.dwait_buffer+GlobalCostDelta)*SS.dwait_delta)
SS.wait = Clamp(round(NewWait,world.tick_lag),SS.dwait_lower,SS.dwait_upper)
if (oldwait != SS.wait)
calculateGCD()
SS.next_fire += SS.wait
++SS.times_fired
sleep(-1)
cost = MC_AVERAGE(cost, world.timeofday - start_time)
if (SubSystemRan)
calculateSScost()
sleep(processing_interval)
else
sleep(50)
/datum/controller/game_controller/proc/calculateSScost()
var/newcost = 0
for(var/datum/subsystem/SS in subsystems)
if (!SS.can_fire)
continue
newcost += SS.cost/(SS.wait/10)
SSCostPerSecond = MC_AVERAGE(SSCostPerSecond,newcost)
#undef MC_AVERAGE
/datum/controller/game_controller/proc/roundHasStarted()
for(var/datum/subsystem/SS in subsystems)
SS.can_fire = 1
SS.next_fire = world.time + rand(0,SS.wait)
/datum/controller/game_controller/proc/Recover()
var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
for(var/varname in master_controller.vars)
switch(varname)
if("tag","bestF","type","parent_type","vars") continue
else
var/varval = master_controller.vars[varname]
if(istype(varval,/datum))
var/datum/D = varval
msg += "\t [varname] = [D.type]\n"
else
msg += "\t [varname] = [varval]\n"
world.log << msg
subsystems = master_controller.subsystems