mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-09 16:14:13 +00:00
Conflicts: code/ATMOSPHERICS/pipe/pipe_dispenser.dm code/game/machinery/computer/HolodeckControl.dm code/game/machinery/embedded_controller/embedded_controller_base.dm code/modules/mining/money_bag.dm code/modules/mob/living/carbon/carbon.dm code/modules/mob/living/silicon/mommi/mommi.dm code/modules/mob/living/simple_animal/friendly/farm_animals.dm code/modules/research/destructive_analyzer.dm code/modules/research/rdconsole.dm code/modules/research/xenoarchaeology/machinery/analysis_base.dm code/modules/research/xenoarchaeology/machinery/artifact_harvester.dm code/modules/research/xenoarchaeology/tools/ano_device_battery.dm
416 lines
12 KiB
Plaintext
416 lines
12 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/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
|
|
|
|
if (isnull(job_master))
|
|
job_master = new /datum/controller/occupations()
|
|
job_master.SetupOccupations()
|
|
job_master.LoadJobs("config/jobs.txt")
|
|
world << "<span class='warning'><B>Job setup complete</span></B>"
|
|
|
|
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()
|
|
setupgenetics()
|
|
setupfactions()
|
|
setup_economy()
|
|
SetupXenoarch()
|
|
cachedamageicons()
|
|
world << "<span class='warning'><B>Caching Jukebox playlists...</span></B>"
|
|
load_juke_playlists()
|
|
world << "<span class='warning'><B>Caching Jukebox playlists complete.</span></B>"
|
|
//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()
|
|
*/
|
|
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()
|
|
world << "<span class='warning'><B>Initializing objects</span></B>"
|
|
sleep(-1)
|
|
//var/last_init_type = null
|
|
for(var/atom/movable/object in world)
|
|
//if(last_init_type != object.type)
|
|
// testing("Initializing [object.type]")
|
|
// last_init_type = object.type
|
|
object.initialize()
|
|
|
|
|
|
world << "<span class='warning'><B>Initializing pipe networks</span></B>"
|
|
sleep(-1)
|
|
for(var/obj/machinery/atmospherics/machine in machines)
|
|
machine.build_network()
|
|
|
|
world << "<span class='warning'><B>Initializing atmos machinery.</span></B>"
|
|
sleep(-1)
|
|
for(var/obj/machinery/atmospherics/unary/U in machines)
|
|
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
|
|
var/obj/machinery/atmospherics/unary/vent_pump/T = U
|
|
T.broadcast_status()
|
|
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
|
|
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
|
|
T.broadcast_status()
|
|
|
|
world << "<span class='warning'><B>Initializations complete.</span></B>"
|
|
sleep(-1)
|
|
|
|
|
|
/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)
|
|
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
|
|
|