diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm index 15774f99c2f..0f9a38b09b3 100644 --- a/code/ATMOSPHERICS/he_pipes.dm +++ b/code/ATMOSPHERICS/he_pipes.dm @@ -54,11 +54,11 @@ if(target.initialize_directions_he & get_dir(target,src)) node2 = target break - + if(!node1 && !node2) del(src) return - + update_icon() return @@ -105,10 +105,10 @@ if(target.initialize_directions_he & get_dir(target,src)) node2 = target break - + if(!node1 && !node2) - del(src) - return + qdel(src) + return update_icon() return diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 2a143c80c51..b303d7d31f4 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -55,9 +55,10 @@ return parent.return_network(reference) -/obj/machinery/atmospherics/pipe/Del() + +/obj/machinery/atmospherics/pipe/Destroy() del(parent) - if(air_temporary) + if(air_temporary && loc) loc.assume_air(air_temporary) ..() @@ -70,7 +71,7 @@ if(istype(W,/obj/item/device/pipe_painter)) return 0 - + if (istype(W, /obj/item/device/pipe_freezer)) if(!src.frozen) // If the pipe is not already frozen user << "\red You begin to freeze the [src]" @@ -88,7 +89,7 @@ "You hear dripping water.") add_fingerprint(user) - return 1 + return 1 if (!istype(W, /obj/item/weapon/wrench)) return ..() @@ -96,7 +97,7 @@ if (level==1 && isturf(T) && T.intact) user << "\red You must remove the plating first." return 1 - + var/datum/gas_mixture/int_air = return_air() var/datum/gas_mixture/env_air = loc.return_air() if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) @@ -129,7 +130,7 @@ /* /obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction) - if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices return ..() if(node) @@ -182,7 +183,7 @@ /obj/machinery/atmospherics/pipe/simple/New() ..() - + // Pipe colors and icon states are handled by an image cache - so color and icon should // be null. For mapping purposes color is defined in the object definitions. icon = null @@ -242,7 +243,7 @@ else if(dir==12) dir = 4 -/obj/machinery/atmospherics/pipe/simple/Del() +/obj/machinery/atmospherics/pipe/simple/Destroy() if(node1) node1.disconnect(src) if(node2) @@ -276,7 +277,7 @@ if (meter.target == src) new /obj/item/pipe_meter(T) del(meter) - del(src) + qdel(src) else if(node1 && node2) overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "intact" + icon_connect_type) else @@ -313,9 +314,9 @@ src.connected_to = c node2 = target break - + if(!node1 && !node2) - del(src) + qdel(src) return var/turf/T = get_turf(src) @@ -359,7 +360,7 @@ layer = 2.39 icon_connect_type = "-supply" color = PIPE_COLOR_BLUE - + /obj/machinery/atmospherics/pipe/simple/visible/yellow color = PIPE_COLOR_YELLOW @@ -394,7 +395,7 @@ layer = 2.39 icon_connect_type = "-supply" color = PIPE_COLOR_BLUE - + /obj/machinery/atmospherics/pipe/simple/visible/universal name="Universal pipe adapter" desc = "An adapter for regular, supply and scrubbers pipes" @@ -567,7 +568,7 @@ else . = PROCESS_KILL -/obj/machinery/atmospherics/pipe/manifold/Del() +/obj/machinery/atmospherics/pipe/manifold/Destroy() if(node1) node1.disconnect(src) if(node2) @@ -620,19 +621,19 @@ if (meter.target == src) new /obj/item/pipe_meter(T) del(meter) - del(src) + qdel(src) else overlays.Cut() overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type) overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type) underlays.Cut() - + var/turf/T = get_turf(src) var/list/directions = list(NORTH, SOUTH, EAST, WEST) var/node1_direction = get_dir(src, node1) var/node2_direction = get_dir(src, node2) var/node3_direction = get_dir(src, node3) - + directions -= dir directions -= add_underlay(T,node1,node1_direction,icon_connect_type) @@ -692,7 +693,7 @@ break if (node3) break - + if(!node1 && !node2 && !node3) del(src) return @@ -804,7 +805,7 @@ else . = PROCESS_KILL -/obj/machinery/atmospherics/pipe/manifold4w/Del() +/obj/machinery/atmospherics/pipe/manifold4w/Destroy() if(node1) node1.disconnect(src) if(node2) @@ -866,13 +867,13 @@ if (meter.target == src) new /obj/item/pipe_meter(T) del(meter) - del(src) + qdel(src) else overlays.Cut() overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type) overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type) underlays.Cut() - + /* var/list/directions = list(NORTH, SOUTH, EAST, WEST) @@ -884,7 +885,7 @@ for(var/D in directions) add_underlay(,D) */ - + var/turf/T = get_turf(src) var/list/directions = list(NORTH, SOUTH, EAST, WEST) var/node1_direction = get_dir(src, node1) @@ -948,7 +949,7 @@ src.connected_to = c node4 = target break - + if(!node1 && !node2 && !node3&& !node4) del(src) return @@ -1059,7 +1060,7 @@ ..() else . = PROCESS_KILL -/obj/machinery/atmospherics/pipe/cap/Del() +/obj/machinery/atmospherics/pipe/cap/Destroy() if(node) node.disconnect(src) @@ -1176,7 +1177,7 @@ else . = PROCESS_KILL -/obj/machinery/atmospherics/pipe/tank/Del() +/obj/machinery/atmospherics/pipe/tank/Destroy() if(node1) node1.disconnect(src) @@ -1263,7 +1264,7 @@ air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - ..() + ..() icon_state = "air" /obj/machinery/atmospherics/pipe/tank/oxygen @@ -1376,7 +1377,7 @@ else parent.mingle_with_turf(loc, volume) -/obj/machinery/atmospherics/pipe/vent/Del() +/obj/machinery/atmospherics/pipe/vent/Destroy() if(node1) node1.disconnect(src) diff --git a/code/__HELPERS/experimental.dm b/code/__HELPERS/experimental.dm index 0966261563b..da9c2a17446 100644 --- a/code/__HELPERS/experimental.dm +++ b/code/__HELPERS/experimental.dm @@ -1,5 +1,5 @@ /* - * Experimental procs by ESwordTheCat. + * Experimental procs by ESwordTheCat! */ /* @@ -15,7 +15,7 @@ * -1, parameter B is not a char * -2, parameter A is not a string */ -/proc/EgijkAeN(const/A, const/B) +/proc/strpos(const/A, const/B) if (istext(A) == 0 || length(A) < 1) return -2 @@ -31,29 +31,24 @@ . = i i = findtext(A, B, i + 1) -/obj/machinery/proc/getArea() - var/area/A = loc.loc - - if (A != myArea) - myArea = A - - . = myArea - /** * Object pooling. * * If this file is named experimental, * well treat this implementation as experimental experimental (redundancy intended). * - * WARNING, only supports /mob and /obj. + * WARNING, only supports /atom/movable (/mob and /obj) */ // Uncomment to show debug messages. //#define DEBUG_OBJECT_POOL -#define MAINTAINING_OBJECT_POOL_COUNT 20 +#define MAINTAINING_OBJECT_POOL_COUNT 500 -var/list/masterPool = list() +var/global/list/masterPool = new + +// Read-only or compile-time vars and special exceptions. +var/list/exclude = list("inhand_states", "loc", "locs", "parent_type", "vars", "verbs", "type", "x", "y", "z") /* * @args @@ -62,27 +57,35 @@ var/list/masterPool = list() * * Example call: getFromPool(/obj/item/weapon/shard, loc) */ -/proc/getFromPool(const/A, const/B) - if (isnull(masterPool[A])) +/proc/getFromPool() + var/A = args[1] + var/list/B = list() + B += (args - A) + if(length(masterPool["[A]"]) <= 0) #ifdef DEBUG_OBJECT_POOL - world << "DEBUG_OBJECT_POOL: new proc has been called ([A])." + world << text("DEBUG_OBJECT_POOL: new proc has been called ([]).", A) #endif + //so the GC knows we're pooling this type. + if(isnull(masterPool["[A]"])) + masterPool["[A]"] = list(new A) + if(B && B.len) + return new A(arglist(B)) + else + return new A() - return new A(B) - - var/atom/movable/Object = masterPool[A][1] - masterPool[A] -= Object - var/objectLength = length(masterPool[A]) + var/atom/movable/O = masterPool["[A]"][1] + masterPool["[A]"] -= O #ifdef DEBUG_OBJECT_POOL - world << "DEBUG_OBJECT_POOL: getFromPool([A]) [objectLength] left." + world << text("DEBUG_OBJECT_POOL: getFromPool([]) [] left.", A, length(masterPool[A])) #endif - - if (!objectLength) - masterPool[A] = null - - Object.loc = B - return Object + if(!O || !istype(O)) + O = new A(arglist(B)) + else + if(length(B)) + O.loc = B[1] + O.New(arglist(B)) + return O /* * @args @@ -93,31 +96,26 @@ var/list/masterPool = list() * * Example call: returnToPool(src) */ -/proc/returnToPool(const/A) - if (!istype(A, /atom/movable)) - return -1 +/proc/returnToPool(const/atom/movable/AM) + if(istype(AM.loc,/mob/living)) + var/mob/living/L = AM.loc + L.unEquip(AM) + if(length(masterPool["[AM.type]"]) > MAINTAINING_OBJECT_POOL_COUNT) + #ifdef DEBUG_OBJECT_POOL + world << text("DEBUG_OBJECT_POOL: returnToPool([]) exceeds [] discarding...", AM.type, MAINTAINING_OBJECT_POOL_COUNT) + #endif - var/atom/movable/Object = A - Object.resetVariables() + qdel(AM, 1) + return - switch(length(masterPool[Object.type])) - if (MAINTAINING_OBJECT_POOL_COUNT to 1.#INF) - #ifdef DEBUG_OBJECT_POOL - world << "DEBUG_OBJECT_POOL: returnToPool([Object.type]) exceeds [num2text(MAINTAINING_OBJECT_POOL_COUNT)] discarding..." - #endif + if(isnull(masterPool["[AM.type]"])) + masterPool["[AM.type]"] = list() - return - if (0) // In a numeric context (like a mathematical operation), null evaluates to 0. - #ifdef DEBUG_OBJECT_POOL - world << "DEBUG_OBJECT_POOL: [Object.type] pool is empty, recreating pool." - #endif - - masterPool[Object.type] = list() - - masterPool[Object.type] += Object + AM.resetVariables() + masterPool["[AM.type]"] += AM #ifdef DEBUG_OBJECT_POOL - world << "DEBUG_OBJECT_POOL: returnToPool([Object.type]) [length(masterPool[Object.type])] left." + world << text("DEBUG_OBJECT_POOL: returnToPool([]) [] left.", AM.type, length(masterPool["[AM.type]"])) #endif #undef MAINTAINING_OBJECT_POOL_COUNT @@ -127,20 +125,48 @@ var/list/masterPool = list() #endif /* - * Override this if the object variables needed to reset. + * if you have a variable that needed to be preserve, override this and call .. * - * Example: see, code\game\objects\items\stacks\sheets\glass.dm - * @/obj/item/weapon/shard - * @resetVariables() + * example + * + * /obj/item/resetVariables() + * ..("var1", "var2", "var3") + * + * however, if the object has a child type an it has overridden resetVariables() + * this should be + * + * /obj/item/resetVariables() + * ..("var1", "var2", "var3", args) + * + * /obj/item/weapon/resetVariables() + * ..("var4") */ -/atom/movable - proc/resetVariables() - var/list/exclude = list("loc", "locs", "parent_type", "vars", "verbs", "type") // Read-only or compile-time vars and whatevs. - exclude += args // Explicit var exclusion - var/list/varsCopy = vars - exclude - var/key +/atom/movable/proc/resetVariables() + loc = null - for (key in varsCopy) - vars[key] = initial(vars[key]) + var/list/exclude = global.exclude + args // explicit var exclusion - vars["loc"] = null // Making sure the loc is null not a compile-time var value. + for(var/key in vars) + if(key in exclude) + continue + + vars[key] = initial(vars[key]) + +/proc/isInTypes(atom/Object, types) + var/prototype = Object.type + Object = null + + for (var/type in params2list(types)) + if (ispath(prototype, text2path(type))) + return 1 + + return 0 + + +/obj/machinery/proc/getArea() + var/area/A = loc.loc + + if (A != myArea) + myArea = A + + . = myArea \ No newline at end of file diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index 5fb552d4384..46662142fba 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -108,7 +108,7 @@ var/const/tk_maxrange = 15 return var/d = get_dist(user, target) - if(focus) + if(focus) d = max(d,get_dist(user,focus)) // whichever is further if(d > tk_maxrange) user << "Your mind won't reach that far." @@ -163,7 +163,7 @@ var/const/tk_maxrange = 15 O.icon_state = "nothing" flick("empdisable",O) spawn(5) - O.delete() + qdel(O) return diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm index 15e0b2e9c8f..7ed1a047a0d 100644 --- a/code/controllers/_DynamicAreaLighting_TG.dm +++ b/code/controllers/_DynamicAreaLighting_TG.dm @@ -160,14 +160,6 @@ atom/movable/New() trueLuminosity = luminosity * luminosity light = new(src) -//Objects with opacity will trigger nearby lights to update at next lighting process. -atom/movable/Destroy() - if(opacity) - if(isturf(loc)) - if(loc:lighting_lumcount > 1) - UpdateAffectingLights() - - ..() //Sets our luminosity. //If we have no light it will create one. diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 062a650c9ba..95ecef88978 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -134,12 +134,12 @@ var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix var/default_laws = 0 //Controls what laws the AI spawns with. - + var/list/station_levels = list(1) // Defines which Z-levels the station exists on. var/list/admin_levels= list(2) // Defines which Z-levels which are for admin functionality, for example including such areas as Central Command and the Syndicate Shuttle var/list/contact_levels = list(1, 5) // Defines which Z-levels which, for example, a Code Red announcement may affect var/list/player_levels = list(1, 3, 4, 5, 6, 7) // Defines all Z-levels a character can typically reach - + var/const/minutes_to_ticks = 60 * 10 // Event settings var/expected_round_length = 60 * 2 * minutes_to_ticks // 2 hours @@ -168,7 +168,7 @@ src.probabilities[M.config_tag] = M.probability if (M.votable) src.votable_modes += M.config_tag - del(M) + qdel(M) src.votable_modes += "secret" /datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist @@ -209,9 +209,9 @@ if ("use_age_restriction_for_jobs") config.use_age_restriction_for_jobs = 1 - + if ("use_age_restriction_for_antags") - config.use_age_restriction_for_antags = 1 + config.use_age_restriction_for_antags = 1 if ("jobs_have_minimal_access") config.jobs_have_minimal_access = 1 @@ -462,7 +462,7 @@ if("max_maint_drones") config.max_maint_drones = text2num(value) - + if("station_levels") config.station_levels = text2numlist(value, ";") @@ -474,7 +474,7 @@ if("player_levels") config.player_levels = text2numlist(value, ";") - + if("expected_round_length") config.expected_round_length = MinutesToTicks(text2num(value)) diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index ff46b6b10b6..a2a6274a8ab 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -1,68 +1,78 @@ -var/datum/controller/failsafe/Failsafe +var/global/datum/controller/failsafe/failsafe -/datum/controller/failsafe // This thing pretty much just keeps poking the master controller - var/processing = 0 - var/processing_interval = 100 //poke the MC every 10 seconds +/datum/controller/failsafe // This thing pretty much just keeps poking the controllers. + processing_interval = 100 // Poke the controllers every 10 seconds. - var/MC_iteration = 0 - var/MC_defcon = 0 //alert level. For every poke that fails this is raised by 1. When it reaches 5 the MC is replaced with a new one. (effectively killing any master_controller.process() and starting a new one) + /* + * Controller alert level. + * For every poke that fails this is raised by 1. + * When it reaches 5 the MC is replaced with a new one + * (effectively killing any controller process() and starting a new one). + */ - var/lighting_iteration = 0 - var/lighting_defcon = 0 //alert level for lighting controller. + // master + var/masterControllerIteration = 0 + var/masterControllerAlertLevel = 0 + + // lighting + var/lightingControllerIteration = 0 + var/lightingControllerAlertLevel = 0 /datum/controller/failsafe/New() - //There can be only one failsafe. Out with the old in with the new (that way we can restart the Failsafe by spawning a new one) - if(Failsafe != src) - if(istype(Failsafe)) - del(Failsafe) - Failsafe = src - Failsafe.process() + . = ..() + // There can be only one failsafe. Out with the old in with the new (that way we can restart the Failsafe by spawning a new one). + if (failsafe != src) + if (istype(failsafe)) + recover() + qdel(failsafe) + + failsafe = src + + failsafe.process() /datum/controller/failsafe/proc/process() processing = 1 + spawn(0) - //set background = 1 - while(1) //more efficient than recursivly calling ourself over and over. background = 1 ensures we do not trigger an infinite loop - if(!master_controller) new /datum/controller/game_controller() //replace the missing master_controller! This should never happen. - if(!lighting_controller) new /datum/controller/lighting() //replace the missing lighting_controller + set background = BACKGROUND_ENABLED + + while(1) // More efficient than recursivly calling ourself over and over. background = 1 ensures we do not trigger an infinite loop. + iteration++ if(processing) - if(master_controller.processing) //only poke if these overrides aren't in effect - if(MC_iteration == controller_iteration) //master_controller hasn't finished processing in the defined interval - switch(MC_defcon) + if(master_controller.processing) // Only poke if these overrides aren't in effect + if(masterControllerIteration == master_controller.iteration) // Master controller hasn't finished processing in the defined interval. + switch(masterControllerAlertLevel) if(0 to 3) - MC_defcon++ + masterControllerAlertLevel++ if(4) - admins << "Warning. The Master Controller has not fired in the last [MC_defcon*processing_interval] ticks. Automatic restart in [processing_interval] ticks." - MC_defcon = 5 + admins << "Warning. The master Controller has not fired in the last [masterControllerAlertLevel * processing_interval] ticks. Automatic restart in [processing_interval] ticks." + masterControllerAlertLevel = 5 if(5) - admins << "Warning. The Master Controller has still not fired within the last [MC_defcon*processing_interval] ticks. Killing and restarting..." - new /datum/controller/game_controller() //replace the old master_controller (hence killing the old one's process) - master_controller.process() //Start it rolling again - MC_defcon = 0 + admins << "Warning. The master Controller has still not fired within the last [masterControllerAlertLevel * processing_interval] ticks. Killing and restarting..." + new /datum/controller/game_controller() // Replace the old master controller (hence killing the old one's process). + master_controller.process() // Start it rolling again. + masterControllerAlertLevel = 0 else - MC_defcon = 0 - MC_iteration = controller_iteration + masterControllerAlertLevel = 0 + masterControllerIteration = master_controller.iteration if(lighting_controller.processing) - if(lighting_iteration == lighting_controller.iteration) //master_controller hasn't finished processing in the defined interval - switch(lighting_defcon) + if(lightingControllerIteration == lighting_controller.iteration) // Lighting controller hasn't finished processing in the defined interval. + switch(lightingControllerAlertLevel) if(0 to 3) - lighting_defcon++ + lightingControllerAlertLevel++ if(4) - admins << "Warning. The Lighting Controller has not fired in the last [lighting_defcon*processing_interval] ticks. Automatic restart in [processing_interval] ticks." - lighting_defcon = 5 + admins << "Warning. The lighting_controller controller has not fired in the last [lightingControllerAlertLevel * processing_interval] ticks. Automatic restart in [processing_interval] ticks." + lightingControllerAlertLevel = 5 if(5) - admins << "Warning. The Lighting Controller has still not fired within the last [lighting_defcon*processing_interval] ticks. Killing and restarting..." - new /datum/controller/lighting() //replace the old lighting_controller (hence killing the old one's process) - lighting_controller.process() //Start it rolling again - lighting_defcon = 0 + admins << "Warning. The lighting_controller controller has still not fired within the last [lightingControllerAlertLevel * processing_interval] ticks. Killing and restarting..." + new /datum/controller/lighting() // Replace the old lighting_controller (hence killing the old one's process). + lighting_controller.process() // Start it rolling again. + lightingControllerAlertLevel = 0 else - lighting_defcon = 0 - lighting_iteration = lighting_controller.iteration - else - MC_defcon = 0 - lighting_defcon = 0 + lightingControllerAlertLevel = 0 + lightingControllerIteration = lighting_controller.iteration - sleep(processing_interval) \ No newline at end of file + sleep(processing_interval) diff --git a/code/controllers/garbage.dm b/code/controllers/garbage.dm index 412a4bdef10..b120d83abcb 100644 --- a/code/controllers/garbage.dm +++ b/code/controllers/garbage.dm @@ -1,124 +1,182 @@ +#define GC_COLLECTIONS_PER_TICK 300 // Was 100. +#define GC_COLLECTION_TIMEOUT (30 SECONDS) +#define GC_FORCE_DEL_PER_TICK 60 +//#define GC_DEBUG -#define GC_COLLECTIONS_PER_TICK 250 // Was 100 -#define GC_COLLECTION_TIMEOUT 100 // 10s -var/global/datum/controller/garbage_collector/garbage -var/global/list/uncollectable_vars=list( - "alpha", - "bestF", - "bounds", - "bound_height", - "bound_width", - "ckey", - "color", - "contents", - "gender", - "group", - "key", - //"loc", - "locs", - "luminosity", - "parent", - "parent_type", - "step_size", - "glide_size", - "gc_destroyed", - "step_x", - "step_y", - "step_z", - "tag", - "thermal_conductivity", - "type", - "vars", - "verbs", - "x", - "y", - "z", -) -/datum/controller/garbage_collector - var/list/queue=list() - var/list/destroyed=list() - var/waiting=0 - var/del_everything=1 - var/turf/trashbin=null +var/list/gc_hard_del_types = new +var/datum/garbage_collector/garbageCollector - New() - trashbin=locate(0,0,CENTCOMM_Z) +/client/verb/gc_dump_hdl() + set name = "(GC) Hard Del List" + set desc = "List types that are hard del()'d by the GC." + set category = "Debug" - proc/AddTrash(var/atom/movable/A) - if(!A) - return - if(del_everything) - del(A) - return - A.loc=trashbin - queue.Add(A) - waiting++ + for(var/A in gc_hard_del_types) + usr << "[A] = [gc_hard_del_types[A]]" - proc/Pop() - var/atom/movable/A = queue[1] - if(!A) - if(isnull(A)) - var/loopcheck = 0 - while(queue.Remove(null)) - loopcheck++ - if(loopcheck > 50) - break - return - if(del_everything) - del(A) - return - if(!istype(A,/atom/movable)) - testing("GC given a [A.type].") - del(A) - return - for(var/vname in A.vars) - if(!issaved(A.vars[vname])) - continue - if(vname in uncollectable_vars) - continue - //testing("Unsetting [vname] in [A.type]!") - A.vars[vname]=null - A.loc=null - destroyed.Add("\ref[A]") - queue.Remove(A) +/datum/garbage_collector + var/list/queue = new + var/del_everything = 0 - proc/process() - for(var/i=0;i= world.time - GC_COLLECTION_TIMEOUT) - // Something's still referring to the qdel'd object. Kill it. - del(A) - destroyed.Remove(refID) + // To let them know how hardworking am I :^). + var/dels_count = 0 + var/hard_dels = 0 + var/soft_dels = 0 -/** -* NEVER USE THIS FOR ANYTHING OTHER THAN /atom/movable -* OTHER TYPES CANNOT BE QDEL'D BECAUSE THEIR LOC IS LOCKED OR THEY DON'T HAVE ONE. -*/ -/proc/qdel(var/atom/movable/A) - if(!A) return - if(!istype(A)) - warning("qdel() passed object of type [A.type]. qdel() can only handle /atom/movable types.") - del(A) +/datum/garbage_collector/proc/addTrash(const/atom/movable/AM) + if(!istype(AM)) return - if(!garbage) - del(A) + + if(del_everything) + del(AM) + hard_dels++ + dels_count++ return - // Let our friend know they're about to get fucked up. - A.Destroy() - garbage.AddTrash(A) + + queue["\ref[AM]"] = world.timeofday + +/datum/garbage_collector/proc/process() + var/remainingCollectionPerTick = GC_COLLECTIONS_PER_TICK + var/remainingForceDelPerTick = GC_FORCE_DEL_PER_TICK + var/collectionTimeScope = world.timeofday - GC_COLLECTION_TIMEOUT + if(narsie_cometh) return //don't even fucking bother, its over. + while(queue.len && --remainingCollectionPerTick >= 0) + var/refID = queue[1] + var/destroyedAtTime = queue[refID] + + if(destroyedAtTime > collectionTimeScope) + break + + var/atom/movable/AM = locate(refID) + if(AM) // Something's still referring to the qdel'd object. del it. + if(isnull(AM.gcDestroyed)) + queue -= refID + continue + if(remainingForceDelPerTick <= 0) + break + + #ifdef GC_DEBUG + WARNING("gc process force delete [AM.type]") + #endif + + AM.hard_deleted = 1 + del AM + + hard_dels++ + remainingForceDelPerTick-- + +#ifdef GC_DEBUG +#undef GC_DEBUG +#endif + +#undef GC_FORCE_DEL_PER_TICK +#undef GC_COLLECTION_TIMEOUT +#undef GC_COLLECTIONS_PER_TICK + +/datum/garbage_collector/proc/dequeue(id) + if (queue) + queue -= id + + dels_count++ + +/* + * NEVER USE THIS FOR ANYTHING OTHER THAN /atom/movable + * OTHER TYPES CANNOT BE QDEL'D BECAUSE THEIR LOC IS LOCKED OR THEY DON'T HAVE ONE. + */ +/proc/qdel(const/atom/movable/AM, ignore_pooling = 0) + if(isnull(AM)) + return + + if(isnull(garbageCollector)) + del(AM) + return + + if(!istype(AM)) + WARNING("qdel() passed object of type [AM.type]. qdel() can only handle /atom/movable types.") + del(AM) + garbageCollector.hard_dels++ + garbageCollector.dels_count++ + return + + //We are object pooling this. + if(("[AM.type]" in masterPool) && !ignore_pooling) + returnToPool(AM) + return + + if(isnull(AM.gcDestroyed)) + // Let our friend know they're about to get fucked up. + AM.Destroy() + + garbageCollector.addTrash(AM) + +/datum/controller + var/processing = 0 + var/iteration = 0 + var/processing_interval = 0 + +/datum/controller/proc/recover() // If we are replacing an existing controller (due to a crash) we attempt to preserve as much as we can. + +/* + * Like Del(), but for qdel. + * Called BEFORE qdel moves shit. + */ +/datum/proc/Destroy() + del(src) /client/proc/qdel_toggle() set name = "Toggle qdel Behavior" set desc = "Toggle qdel usage between normal and force del()." set category = "Debug" - garbage.del_everything = !garbage.del_everything - world << "GC: qdel turned [garbage.del_everything?"off":"on"]." - log_admin("[key_name(usr)] turned qdel [garbage.del_everything?"off":"on"].") - message_admins("\blue [key_name(usr)] turned qdel [garbage.del_everything?"off":"on"].", 1) \ No newline at end of file + garbageCollector.del_everything = !garbageCollector.del_everything + world << "GC: qdel turned [garbageCollector.del_everything ? "off" : "on"]." + log_admin("[key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].") + message_admins("\blue [key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].", 1) + +/*/client/var/running_find_references + +/atom/verb/find_references() + set category = "Debug" + set name = "Find References" + set background = 1 + set src in world + + if(!usr || !usr.client) + return + + if(usr.client.running_find_references) + testing("CANCELLED search for references to a [usr.client.running_find_references].") + usr.client.running_find_references = null + return + + if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No") + return + qdel(src) + // Remove this object from the list of things to be auto-deleted. + if(garbageCollector) + garbageCollector.queue -= "\ref[src]" + + usr.client.running_find_references = type + testing("Beginning search for references to a [type].") + var/list/things = list() + for(var/client/thing) + things += thing + for(var/datum/thing) + things += thing + for(var/atom/thing) + things += thing + for(var/event/thing) + things += thing + testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)") + for(var/datum/thing in things) + if(!usr.client.running_find_references) return + for(var/varname in thing.vars) + var/variable = thing.vars[varname] + if(variable == src) + testing("Found [src.type] \ref[src] in [thing.type]'s [varname] var.") + else if(islist(variable)) + if(src in variable) + testing("Found [src.type] \ref[src] in [thing.type]'s [varname] list var.") + testing("Completed search for references to a [type].") + usr.client.running_find_references = null +*/ \ No newline at end of file diff --git a/code/controllers/lighting_controller.dm b/code/controllers/lighting_controller.dm index c118fa43abb..fd1a2305cb1 100644 --- a/code/controllers/lighting_controller.dm +++ b/code/controllers/lighting_controller.dm @@ -1,10 +1,8 @@ var/datum/controller/lighting/lighting_controller = new () datum/controller/lighting - var/processing = 0 - var/processing_interval = 5 //setting this too low will probably kill the server. Don't be silly with it! + processing_interval = 5 //setting this too low will probably kill the server. Don't be silly with it! var/process_cost = 0 - var/iteration = 0 var/lighting_states = 7 diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 518cfafd522..98c44b42b6e 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -11,7 +11,6 @@ var/global/air_processing_killed = 0 var/global/pipe_processing_killed = 0 datum/controller/game_controller - var/processing = 0 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 @@ -28,7 +27,7 @@ datum/controller/game_controller var/events_cost = 0 var/puddles_cost var/ticker_cost = 0 - var/gc_cost = 0 + var/garbageCollectorCost = 0 var/total_cost = 0 var/last_thing_processed @@ -36,6 +35,7 @@ datum/controller/game_controller var/list/shuttle_list // For debugging and VV var/datum/ore_distribution/asteroid_ore_map // For debugging and VV. + 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. @@ -71,9 +71,6 @@ datum/controller/game_controller/proc/setup() ticker = new /datum/controller/gameticker() */ - if(!garbage) - garbage = new /datum/controller/garbage_collector() - color_windows_init() setup_objects() @@ -134,7 +131,7 @@ datum/controller/game_controller/proc/process() spawn(0) //set background = 1 while(1) //far more efficient than recursively calling ourself - if(!Failsafe) new /datum/controller/failsafe() + if(!failsafe) new /datum/controller/failsafe() if(processing) @@ -246,12 +243,12 @@ datum/controller/game_controller/proc/process() // GC timer = world.timeofday - last_thing_processed = garbage.type - garbage.process() - gc_cost = (world.timeofday - timer) / 10 + 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 + aibots_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + puddles_cost + ticker_cost + gc_cost + total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + aibots_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + puddles_cost + ticker_cost + garbageCollectorCost var/end_time = world.timeofday if(end_time < start_time) //why not just use world.time instead? diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 20252b0403b..90e877b0443 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -49,7 +49,7 @@ return -/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event")) +/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Scheduler")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -59,18 +59,15 @@ if("Master") debug_variables(master_controller) feedback_add_details("admin_verb","DMC") - if("Failsafe") - debug_variables(Failsafe) - feedback_add_details("admin_verb","DFailsafe") + if ("failsafe") + debug_variables(failsafe) + feedback_add_details("admin_verb", "dfailsafe") if("Ticker") debug_variables(ticker) feedback_add_details("admin_verb","DTicker") if("Lighting") debug_variables(lighting_controller) feedback_add_details("admin_verb","DLighting") - if("Garbage") - debug_variables(garbage) - feedback_add_details("admin_verb","DGarbage") if("Air") debug_variables(air_master) feedback_add_details("admin_verb","DAir") @@ -103,7 +100,13 @@ feedback_add_details("admin_verb","DCameras") if("Event") debug_variables(event_manager) - feedback_add_details("admin_verb","DEvent") - + feedback_add_details("admin_verb","DEvent") + if("Garbage") + debug_variables(garbageCollector) + feedback_add_details("admin_verb","DGarbage") + if("Scheduler") + debug_variables(processScheduler) + feedback_add_details("admin_verb","DprocessScheduler") + message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/game/atoms.dm b/code/game/atoms.dm index fa22e742970..61b63bb6a9d 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1,3 +1,6 @@ +var/global/list/del_profiling = list() +var/global/list/gdel_profiling = list() +var/global/list/ghdel_profiling = list() /atom layer = 2 var/level = 2 @@ -24,16 +27,18 @@ // Garbage collection var/gc_destroyed=null -/atom/Del() - // Pass to Destroy(). - if(!gc_destroyed) - Destroy() - ..() -/atom/proc/Destroy() - gc_destroyed=world.time +/atom/Destroy() + SetOpacity(0) + if(reagents) + reagents.Destroy() + reagents = null + + // Idea by ChuckTheSheep to make the object even more unreferencable. + invisibility = 101 + /atom/proc/CheckParts() return @@ -242,7 +247,7 @@ its easier to just keep the beam vertical. return /atom/proc/emag_act() - return + return /atom/proc/hitby(atom/movable/AM as mob|obj) if (density) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 28c188467b4..419f17b24ad 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -15,13 +15,67 @@ var/mob/pulledby = null var/area/areaMaster - + var/hard_deleted = 0 /atom/movable/New() . = ..() areaMaster = get_area_master(src) +/atom/movable/Destroy() + if(opacity) + if(isturf(loc)) + if(loc:lighting_lumcount > 1) + UpdateAffectingLights() + gcDestroyed = "Bye, world!" + tag = null + loc = null +/* + if(istype(beams) && beams.len) + for(var/obj/effect/beam/B in beams) + if(B && B.target == src) + B.target = null + if(B.master && B.master.target == src) + B.master.target = null + beams.len = 0 +*/ + ..() + +/proc/delete_profile(var/type, code = 0) + if(!ticker || !ticker.current_state < 3) return + switch(code) + if(0) + if (!("[type]" in del_profiling)) + del_profiling["[type]"] = 0 + + del_profiling["[type]"] += 1 + if(1) + if (!("[type]" in ghdel_profiling)) + ghdel_profiling["[type]"] = 0 + + ghdel_profiling["[type]"] += 1 + if(2) + if (!("[type]" in gdel_profiling)) + gdel_profiling["[type]"] = 0 + + gdel_profiling["[type]"] += 1 + if(garbageCollector) + garbageCollector.soft_dels++ + +/atom/movable/Del() + if (gcDestroyed) + garbageCollector.dequeue("\ref[src]") + + if (hard_deleted) + delete_profile("[type]", 1) + else + delete_profile("[type]", 2) + else // direct del calls or nulled explicitly. + delete_profile("[type]", 0) + Destroy() + + ..() + // Used in shuttle movement and AI eye stuff. // Primarily used to notify objects being moved by a shuttle/bluespace fuckup. /atom/movable/proc/setLoc(var/T, var/teleported=0) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 1f98e54cb75..197da35056d 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -25,7 +25,8 @@ /obj/structure/Destroy() if(hascall(src, "unbuckle")) src:unbuckle() - + ..() + /obj/structure/mech_melee_attack(obj/mecha/M) if(M.damtype == "brute") M.occupant_message("You hit [src].") diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm index ea3b35be1ae..6ed7da87a3b 100644 --- a/code/game/objects/structures/musician.dm +++ b/code/game/objects/structures/musician.dm @@ -19,7 +19,7 @@ instrumentDir = dir instrumentObj = obj -/datum/song/proc/Destroy() +/datum/song/Destroy() instrumentObj = null return diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index bf1b9577b21..94ad7725c1b 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -131,9 +131,8 @@ var/list/mechtoys = list( var/comment = null /datum/controller/supply - var/processing = 1 - var/processing_interval = 300 - var/iteration = 0 + processing = 1 + processing_interval = 300 //supply points var/points = 50 var/points_per_process = 1 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 144790401d0..cac65e0a0e7 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -855,7 +855,7 @@ var/list/slot_equipment_priority = list( \ return 0 src << message return 1 - + /mob/proc/is_muzzled() return 0 @@ -873,25 +873,14 @@ var/list/slot_equipment_priority = list( \ stat(null, "CPU:\t[world.cpu]") stat(null, "Instances:\t[world.contents.len]") - if(master_controller) - /* HANDLED THROUGH PROCESS SCHEDULER - stat(null, "MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])") - stat(null, "Air-[master_controller.air_cost]") - stat(null, "Sun-[master_controller.sun_cost]") - stat(null, "Mob-[master_controller.mobs_cost]\t#[mob_list.len]") - stat(null, "Dis-[master_controller.diseases_cost]\t#[active_diseases.len]") - stat(null, "Mch-[master_controller.machines_cost]\t#[machines.len]") - stat(null, "Bots-[master_controller.aibots_cost]\t#[aibots.len]") - stat(null, "Obj-[master_controller.objects_cost]\t#[processing_objects.len]") - stat(null, "PiNet-[master_controller.networks_cost]\t#[pipe_networks.len]") - stat(null, "PoNet-[master_controller.powernets_cost]\t#[powernets.len]") - stat(null, "NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]") -// stat(null, "GC-[master_controller.gc_cost]\t#[garbage.queue.len]") - stat(null, "Tick-[master_controller.ticker_cost]")*/ - stat(null,"Events-[master_controller.events_cost]\t#[event_manager.active_events.len]") - stat(null, "ALL-[master_controller.total_cost]") + if (garbageCollector) + stat(null, "\tqdel - [garbageCollector.del_everything ? "off" : "on"]") + stat(null, "\ton queue - [garbageCollector.queue.len]") + stat(null, "\ttotal delete - [garbageCollector.dels_count]") + stat(null, "\tsoft delete - [garbageCollector.soft_dels]") + stat(null, "\thard delete - [garbageCollector.hard_dels]") else - stat(null, "MasterController-ERROR") + stat(null, "Garbage Controller is not running.") if(processScheduler.getIsRunning()) var/datum/controller/process/process @@ -926,6 +915,9 @@ var/list/slot_equipment_priority = list( \ process = processScheduler.getProcess("disease") stat(null, "DIS([active_diseases.len])\t - #[process.getTicks()]\t - [process.getLastRunTime()]") + process = processScheduler.getProcess("garbage") + stat(null, "GAR\t - #[process.getTicks()]\t - [process.getLastRunTime()]") + //process = processScheduler.getProcess("sun") //stat(null, "SUN\t - #[process.getTicks()]\t - [process.getLastRunTime()]") diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index c9726924f43..3af4d2fbf2c 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -1,6 +1,7 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 // Added spess ghoasts/cameras to this so they don't add to the lag. - N3X +var/global/narsie_cometh = 0 var/global/list/uneatable = list( /turf/space, /obj/effect/overlay, @@ -508,6 +509,7 @@ var/global/list/uneatable = list( if(emergency_shuttle && emergency_shuttle.can_call()) emergency_shuttle.call_evac() emergency_shuttle.launch_time = 0 // Cannot recall + narsie_cometh = 1 /obj/machinery/singularity/narsie/proc/spawn_animation() @@ -541,7 +543,7 @@ var/global/list/uneatable = list( if(istype(A,/obj/)) var/obj/O = A O.ex_act(1.0) - if(O) del(O) + if(O) qdel(O) else if(isturf(A)) var/turf/T = A @@ -565,7 +567,7 @@ var/global/list/uneatable = list( var/obj/O = A machines -= O processing_objects -= O - O.loc = null + qdel(O) else if(isturf(A)) var/turf/T = A if(istype(T,/turf/simulated/wall)) diff --git a/paradise.dme b/paradise.dme index a60078bd76c..c7692b54575 100644 --- a/paradise.dme +++ b/paradise.dme @@ -181,6 +181,7 @@ #include "code\controllers\Processes\disease.dm" #include "code\controllers\Processes\emergencyShuttle.dm" #include "code\controllers\Processes\event.dm" +#include "code\controllers\Processes\garbage.dm" #include "code\controllers\Processes\inactivity.dm" #include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm"