mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 18:32:03 +00:00
Moves turfs list creation to initialize Moves some mine turfs work to initialize Swaps the order in which the process scheduler and master controller are initialized so that the process scheduler setups have the turfs list
479 lines
13 KiB
Plaintext
479 lines
13 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)
|
|
//WIP, needs lots of work still
|
|
|
|
var/global/datum/controller/game_controller/master_controller //Set in world.New()
|
|
|
|
var/global/last_tick_duration = 0
|
|
|
|
var/global/air_processing_killed = 0
|
|
var/global/pipe_processing_killed = 0
|
|
|
|
#ifdef PROFILE_MACHINES
|
|
// /type = time this tick
|
|
var/list/machine_profiling=list()
|
|
#endif
|
|
|
|
/datum/controller/game_controller
|
|
var/breather_ticks = 2 //a somewhat crude attempt to iron over the 'bumps' caused by high-cpu use by letting the MC have a breather for this many ticks after every loop
|
|
var/minimum_ticks = 20 //The minimum length of time between MC ticks
|
|
|
|
var/air_cost = 0
|
|
var/sun_cost = 0
|
|
var/mobs_cost = 0
|
|
var/diseases_cost = 0
|
|
var/machines_cost = 0
|
|
var/objects_cost = 0
|
|
var/networks_cost = 0
|
|
var/powernets_cost = 0
|
|
var/nano_cost = 0
|
|
var/events_cost = 0
|
|
var/ticker_cost = 0
|
|
var/garbageCollectorCost = 0
|
|
var/total_cost = 0
|
|
|
|
var/last_thing_processed
|
|
var/mob/list/expensive_mobs = list()
|
|
var/rebuild_active_areas = 0
|
|
|
|
var/initialized = 0 // Everything initialized? (Delays game start timer until shit is actually loaded)
|
|
|
|
var/global/datum/garbage_collector/garbageCollector
|
|
|
|
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)
|
|
log_debug("Rebuilding Master Controller")
|
|
|
|
if (istype(master_controller))
|
|
recover()
|
|
qdel(master_controller)
|
|
|
|
master_controller = src
|
|
|
|
var/watch=0
|
|
if (isnull(job_master))
|
|
watch = start_watch()
|
|
job_master = new /datum/controller/occupations()
|
|
job_master.SetupOccupations()
|
|
job_master.LoadJobs("config/jobs.txt")
|
|
// to_chat(world, "<span class='danger'>Job setup complete in </span>")
|
|
log_startup_progress("Job setup complete in [stop_watch(watch)]s.")
|
|
|
|
if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
|
|
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
|
|
/*if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()*/
|
|
/*
|
|
if(global.garbageCollector)
|
|
garbageCollector = global.garbageCollector
|
|
*/
|
|
datum/controller/game_controller/proc/setup()
|
|
world.tick_lag = config.Ticklag
|
|
|
|
// notify the other process that we started up
|
|
socket_talk = new /datum/socket_talk()
|
|
socket_talk.send_raw("type=startup")
|
|
|
|
createRandomZlevel()
|
|
/*
|
|
if(!air_master)
|
|
air_master = new /datum/controller/air_system()
|
|
air_master.Setup()
|
|
|
|
if(!ticker)
|
|
ticker = new /datum/controller/gameticker()
|
|
|
|
if(!global.garbageCollector)
|
|
global.garbageCollector = new
|
|
garbageCollector = global.garbageCollector
|
|
*/
|
|
|
|
setup_objects() // Most log_startup spam happens here
|
|
setupgenetics()
|
|
setupfactions()
|
|
setup_economy()
|
|
SetupXenoarch()
|
|
var/watch=start_watch()
|
|
log_startup_progress("Caching damage icons...")
|
|
cachedamageicons()
|
|
log_startup_progress(" Finished caching damage icons in [stop_watch(watch)]s.")
|
|
|
|
buildcamlist()
|
|
|
|
if(config.media_base_url)
|
|
watch = start_watch()
|
|
log_startup_progress("Caching jukebox playlists...")
|
|
load_juke_playlists()
|
|
log_startup_progress(" Finished caching jukebox playlists in [stop_watch(watch)]s.")
|
|
|
|
//if(map && map.dorf)
|
|
//mining_surprises = typesof(/mining_surprise/dorf) - /mining_surprise/dorf
|
|
//max_secret_rooms += 2
|
|
for(var/i=0, i<max_secret_rooms, i++)
|
|
//if(map && map.dorf)
|
|
//make_dorf_secret()
|
|
//else
|
|
make_mining_asteroid_secret()
|
|
|
|
//if(config.socket_talk)
|
|
// keepalive()
|
|
/*
|
|
spawn(0)
|
|
if(ticker)
|
|
ticker.pregame()
|
|
|
|
lighting_controller.Initialize()
|
|
*/
|
|
initialized=1
|
|
|
|
datum/controller/game_controller/proc/buildcamlist()
|
|
adv_camera.camerasbyzlevel = list()
|
|
for(var/key in adv_camera.zlevels)
|
|
adv_camera.camerasbyzlevel["[key]"] = list()
|
|
//camerasbyzlevel = list("1" = list(), "5" = list())
|
|
if(!istype(cameranet) || !istype(cameranet.cameras) || !cameranet.cameras.len)
|
|
world.log << "cameranet has not been initialized before us, finding cameras manually."
|
|
for(var/obj/machinery/camera/C in world) //can't use machines list because cameras are removed from it.
|
|
if(C.z == 1 || C.z == 5)
|
|
var/list/ourlist = adv_camera.camerasbyzlevel["[C.z]"]
|
|
ourlist += C
|
|
else
|
|
for(var/obj/machinery/camera/C in cameranet.cameras) //can't use machines list because cameras are removed from it.
|
|
if(C.z == 1 || C.z == 5)
|
|
var/list/ourlist = adv_camera.camerasbyzlevel["[C.z]"]
|
|
ourlist += C
|
|
for(var/key in adv_camera.camerasbyzlevel)
|
|
var/list/keylist = adv_camera.camerasbyzlevel[key]
|
|
world.log << "[key] has [keylist.len] entries"
|
|
|
|
adv_camera.initialized = 1
|
|
|
|
datum/controller/game_controller/proc/cachedamageicons()
|
|
var/mob/living/carbon/human/H = new(locate(1,1,2))
|
|
var/datum/species/list/slist = list(new /datum/species/human, new /datum/species/vox, new /datum/species/diona)
|
|
var/icon/DI
|
|
var/species_blood
|
|
for(var/datum/species/S in slist)
|
|
species_blood = (S.blood_color == "#A10808" ? "" : S.blood_color)
|
|
testing("Generating [S], Blood([species_blood])")
|
|
for(var/datum/organ/external/O in H.organs)
|
|
//testing("[O] part")
|
|
for(var/brute = 1 to 3)
|
|
for(var/burn = 1 to 3)
|
|
var/damage_state = "[brute][burn]"
|
|
DI = icon('icons/mob/dam_human.dmi', "[damage_state]") // the damage icon for whole human
|
|
DI.Blend(icon('icons/mob/dam_mask.dmi', O.icon_name), ICON_MULTIPLY)
|
|
if(species_blood)
|
|
DI.Blend(S.blood_color, ICON_MULTIPLY)
|
|
//testing("Completed [damage_state]/[O.icon_name]/[species_blood]")
|
|
damage_icon_parts["[damage_state]/[O.icon_name]/[species_blood]"] = DI
|
|
del(H)
|
|
|
|
/datum/controller/game_controller/proc/setup_objects()
|
|
var/watch = start_watch()
|
|
var/overwatch = start_watch() // Overall.
|
|
|
|
log_startup_progress("Populating asset cache...")
|
|
populate_asset_cache()
|
|
log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
|
|
|
|
watch = start_watch()
|
|
log_startup_progress("Initializing objects...")
|
|
//sleep(-1) // Why
|
|
//var/last_init_type = null
|
|
var/count=0
|
|
for(var/atom/movable/object in world)
|
|
//if(last_init_type != object.type)
|
|
// testing("Initializing [object.type]")
|
|
// last_init_type = object.type
|
|
object.initialize()
|
|
count++
|
|
log_startup_progress(" Initialized [count] objects in [stop_watch(watch)]s.")
|
|
|
|
watch = start_watch()
|
|
count=0
|
|
log_startup_progress("Initializing pipe networks...")
|
|
//sleep(-1)
|
|
for(var/obj/machinery/atmospherics/machine in atmos_machines)
|
|
machine.build_network()
|
|
count++
|
|
log_startup_progress(" Initialized [count] pipe networks in [stop_watch(watch)]s.")
|
|
|
|
watch = start_watch()
|
|
count=0
|
|
log_startup_progress("Initializing atmos machinery...")
|
|
//sleep(-1)
|
|
for(var/obj/machinery/atmospherics/unary/U in atmos_machines)
|
|
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
|
|
var/obj/machinery/atmospherics/unary/vent_pump/T = U
|
|
T.broadcast_status()
|
|
count++
|
|
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
|
|
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
|
|
T.broadcast_status()
|
|
count++
|
|
log_startup_progress(" Initialized [count] atmos devices in [stop_watch(watch)]s.")
|
|
|
|
spawn()
|
|
watch = start_watch()
|
|
log_startup_progress("Generating in-game minimaps...")
|
|
generateMiniMaps()
|
|
log_startup_progress(" Finished minimaps in [stop_watch(watch)]s.")
|
|
|
|
log_startup_progress("Finished initializations in [stop_watch(overwatch)]s.")
|
|
|
|
|
|
|
|
/datum/controller/game_controller/proc/process()
|
|
processing = 1
|
|
|
|
spawn (0)
|
|
set background = BACKGROUND_ENABLED
|
|
|
|
while (1) // Far more efficient than recursively calling ourself.
|
|
if (isnull(failsafe))
|
|
new /datum/controller/failsafe()
|
|
|
|
if (processing)
|
|
iteration++
|
|
var/timer
|
|
var/start_time = world.timeofday
|
|
|
|
vote.process()
|
|
//process_newscaster()
|
|
|
|
//AIR
|
|
|
|
if(!air_processing_killed)
|
|
timer = world.timeofday
|
|
last_thing_processed = air_master.type
|
|
|
|
if(!air_master.Tick()) //Runtimed.
|
|
air_master.failed_ticks++
|
|
if(air_master.failed_ticks > 5)
|
|
to_chat(world, "<font color='red'><b>RUNTIMES IN ATMOS TICKER. Killing air simulation!</font></b>")
|
|
world.log << "### ZAS SHUTDOWN"
|
|
message_admins("ZASALERT: unable to run [air_master.tick_progress], shutting down!")
|
|
log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]")
|
|
air_processing_killed = 1
|
|
air_master.failed_ticks = 0
|
|
|
|
air_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//SUN
|
|
timer = world.timeofday
|
|
last_thing_processed = sun.type
|
|
sun.calc_position()
|
|
sun_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//MOBS
|
|
timer = world.timeofday
|
|
processMobs()
|
|
mobs_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//DISEASES
|
|
timer = world.timeofday
|
|
processDiseases()
|
|
diseases_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//MACHINES
|
|
timer = world.timeofday
|
|
processMachines()
|
|
machines_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//OBJECTS
|
|
timer = world.timeofday
|
|
processObjects()
|
|
objects_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//PIPENETS
|
|
if(!pipe_processing_killed)
|
|
timer = world.timeofday
|
|
processPipenets()
|
|
networks_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//POWERNETS
|
|
timer = world.timeofday
|
|
processPowernets()
|
|
powernets_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//NANO UIS
|
|
timer = world.timeofday
|
|
processNano()
|
|
nano_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//EVENTS
|
|
timer = world.timeofday
|
|
processEvents()
|
|
events_cost = (world.timeofday - timer) / 10
|
|
|
|
//TICKER
|
|
timer = world.timeofday
|
|
last_thing_processed = ticker.type
|
|
ticker.process()
|
|
ticker_cost = (world.timeofday - timer) / 10
|
|
|
|
timer = world.timeofday
|
|
last_thing_processed = garbageCollector.type
|
|
garbageCollector.process()
|
|
garbageCollectorCost = (world.timeofday - timer) / 10
|
|
|
|
//TIMING
|
|
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + ticker_cost + garbageCollectorCost
|
|
|
|
var/end_time = world.timeofday
|
|
if(end_time < start_time)
|
|
start_time -= 864000 //deciseconds in a day
|
|
sleep( round(minimum_ticks - (end_time - start_time),1) )
|
|
else
|
|
sleep(10)
|
|
|
|
datum/controller/game_controller/proc/processMobs()
|
|
var/i = 1
|
|
expensive_mobs.len = 0
|
|
while(i<=mob_list.len)
|
|
var/mob/M = mob_list[i]
|
|
if(M)
|
|
var/clock = world.timeofday
|
|
last_thing_processed = M.type
|
|
M.Life()
|
|
if((world.timeofday - clock) > 1)
|
|
expensive_mobs += M
|
|
i++
|
|
continue
|
|
if(!mob_list.Remove(null))
|
|
mob_list.Cut(i,i+1)
|
|
|
|
/datum/controller/game_controller/proc/processDiseases()
|
|
for (var/datum/disease/Disease in active_diseases)
|
|
if(Disease)
|
|
last_thing_processed = Disease.type
|
|
Disease.process()
|
|
continue
|
|
|
|
active_diseases -= Disease
|
|
|
|
/datum/controller/game_controller/proc/processMachines()
|
|
#ifdef PROFILE_MACHINES
|
|
machine_profiling.len = 0
|
|
#endif
|
|
|
|
for (var/obj/machinery/Machinery in machines)
|
|
if (Machinery && Machinery.loc)
|
|
last_thing_processed = Machinery.type
|
|
|
|
#ifdef PROFILE_MACHINES
|
|
var/start = world.timeofday
|
|
#endif
|
|
|
|
if(PROCESS_KILL == Machinery.process())
|
|
Machinery.inMachineList = 0
|
|
machines.Remove(Machinery)
|
|
continue
|
|
|
|
if (Machinery && Machinery.use_power)
|
|
Machinery.auto_use_power()
|
|
|
|
#ifdef PROFILE_MACHINES
|
|
var/end = world.timeofday
|
|
|
|
if (!(Machinery.type in machine_profiling))
|
|
machine_profiling[Machinery.type] = 0
|
|
|
|
machine_profiling[Machinery.type] += (end - start)
|
|
#endif
|
|
|
|
|
|
/datum/controller/game_controller/proc/processObjects()
|
|
for (var/obj/Object in processing_objects)
|
|
if (Object && Object.loc)
|
|
last_thing_processed = Object.type
|
|
Object.process()
|
|
continue
|
|
|
|
processing_objects -= Object
|
|
|
|
// Hack.
|
|
for (var/turf/unsimulated/wall/supermatter/SM in processing_objects)
|
|
if (SM)
|
|
last_thing_processed = SM.type
|
|
SM.process()
|
|
continue
|
|
|
|
processing_objects -= SM
|
|
|
|
/datum/controller/game_controller/proc/processPipenets()
|
|
last_thing_processed = /datum/pipe_network
|
|
|
|
for (var/datum/pipe_network/Pipe_Network in pipe_networks)
|
|
if(Pipe_Network)
|
|
Pipe_Network.process()
|
|
continue
|
|
|
|
pipe_networks -= Pipe_Network
|
|
|
|
/datum/controller/game_controller/proc/processPowernets()
|
|
last_thing_processed = /datum/powernet
|
|
|
|
for (var/datum/powernet/Powernet in powernets)
|
|
if (Powernet)
|
|
Powernet.reset()
|
|
continue
|
|
|
|
powernets -= Powernet
|
|
|
|
/datum/controller/game_controller/proc/processNano()
|
|
for (var/datum/nanoui/Nanoui in nanomanager.processing_uis)
|
|
if (Nanoui)
|
|
Nanoui.process()
|
|
continue
|
|
|
|
nanomanager.processing_uis -= Nanoui
|
|
|
|
/datum/controller/game_controller/proc/processEvents()
|
|
last_thing_processed = /datum/event
|
|
|
|
for (var/datum/event/Event in events)
|
|
if (Event)
|
|
Event.process()
|
|
continue
|
|
|
|
events -= Event
|
|
|
|
checkEvent()
|
|
|
|
datum/controller/game_controller/recover() //Mostly a placeholder for now.
|
|
. = ..()
|
|
var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
|
|
for(var/varname in master_controller.vars)
|
|
switch(varname)
|
|
if("tag","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
|