diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index fe19d7a5596..041a6283e7c 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -14,5 +14,6 @@ #define GC_QUEUED_FOR_HARD_DEL -2 #define GC_CURRENTLY_BEING_QDELETED -3 -#define QDELETED(X) (!X || X.gc_destroyed) +#define QDELING(X) (X.gc_destroyed) +#define QDELETED(X) (!X || QDELING(X)) #define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 4596c79ef1e..6143022993e 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -20,6 +20,23 @@ #define FLIGHTSUIT_PROCESSING_NONE 0 #define FLIGHTSUIT_PROCESSING_FULL 1 +#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize +#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE) +#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE) + +#define INITIALIZE_HINT_NORMAL 0 //Nothing happens +#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize +#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom + +//type and all subtypes should always call Initialize in New() +#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\ + ..();\ + if(!initialized) {\ + args[1] = TRUE;\ + SSatoms.InitAtom(src, args);\ + }\ +} + // Subsystem init_order, from highest priority to lowest priority // The numbers just define the ordering, they are meaningless otherwise. diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 206a9fabc1a..af210a274c0 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -544,7 +544,7 @@ plane = SPLASHSCREEN_PLANE var/client/holder -/obj/screen/splash/New(client/C, visible, use_previous_title) +/obj/screen/splash/New(client/C, visible, use_previous_title) //TODO: Make this use INITIALIZE_IMMEDIATE holder = C if(!visible) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 99f6a148a48..2be7139a27b 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -3,7 +3,9 @@ name = "Initializing..." var/target -/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical +INITIALIZE_IMMEDIATE(/obj/effect/statclick) + +/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical ..() name = text src.target = target diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 4ca35e434d2..98e3ba2330c 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -1,6 +1,7 @@ -#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize -#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE) -#define INITIALIZATION_INNEW_REGULAR 2 //New should call Initialize(FALSE) +#define BAD_INIT_QDEL_BEFORE 1 +#define BAD_INIT_DIDNT_INIT 2 +#define BAD_INIT_SLEPT 4 +#define BAD_INIT_NO_HINT 8 SUBSYSTEM_DEF(atoms) name = "Atoms" @@ -11,6 +12,9 @@ SUBSYSTEM_DEF(atoms) var/old_initialized var/list/late_loaders + var/list/created_atoms + + var/list/BadInitializeCalls = list() /datum/controller/subsystem/atoms/Initialize(timeofday) GLOB.fire_overlay.appearance_flags = RESET_COLOR @@ -19,64 +23,82 @@ SUBSYSTEM_DEF(atoms) InitializeAtoms() return ..() -/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms = null) +/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms) if(initialized == INITIALIZATION_INSSATOMS) return initialized = INITIALIZATION_INNEW_MAPLOAD - var/static/list/NewQdelList = list() - + LAZYINITLIST(late_loaders) + + var/count + var/list/mapload_arg = list(TRUE) if(atoms) + created_atoms = list() + count = atoms.len for(var/I in atoms) var/atom/A = I - if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call - if(QDELETED(A)) - if(!(NewQdelList[A.type])) - WARNING("Found new qdeletion in type [A.type]!") - NewQdelList[A.type] = TRUE - continue - var/start_tick = world.time - if(A.Initialize(TRUE)) - LAZYADD(late_loaders, A) - if(start_tick != world.time) - WARNING("[A]: [A.type] slept during it's Initialize!") + if(!A.initialized) + if(InitAtom(I, mapload_arg)) + atoms -= I CHECK_TICK - testing("Initialized [atoms.len] atoms") else - #ifdef TESTING - var/count = 0 - #endif + count = 0 for(var/atom/A in world) - if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call - if(QDELETED(A)) - if(!(NewQdelList[A.type])) - WARNING("Found new qdeletion in type [A.type]!") - NewQdelList[A.type] = TRUE - continue - var/start_tick = world.time - if(A.Initialize(TRUE)) - LAZYADD(late_loaders, A) - #ifdef TESTING - else - ++count - #endif TESTING - if(start_tick != world.time) - WARNING("[A]: [A.type] slept during it's Initialize!") + if(!A.initialized) + InitAtom(A, mapload_arg) + ++count CHECK_TICK - testing("Roundstart initialized [count] atoms") + + log_world("Initialized [count] atoms") initialized = INITIALIZATION_INNEW_REGULAR - for(var/I in late_loaders) - var/atom/A = I - var/start_tick = world.time - A.Initialize(FALSE) - if(start_tick != world.time) - WARNING("[A]: [A.type] slept during it's Initialize!") - CHECK_TICK - testing("Late-initialized [LAZYLEN(late_loaders)] atoms") - LAZYCLEARLIST(late_loaders) + if(late_loaders.len) + for(var/I in late_loaders) + var/atom/A = I + A.LateInitialize() + testing("Late initialized [late_loaders.len] atoms") + late_loaders.Cut() + + if(atoms) + . = created_atoms + atoms + created_atoms = null + +/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments) + var/the_type = A.type + if(QDELING(A)) + BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE + return TRUE + + var/start_tick = world.time + + var/result = A.Initialize(arglist(arguments)) + + if(start_tick != world.time) + BadInitializeCalls[the_type] |= BAD_INIT_SLEPT + + var/qdeleted = FALSE + + if(result != INITIALIZE_HINT_NORMAL) + switch(result) + if(INITIALIZE_HINT_LATELOAD) + if(arguments[1]) //mapload + late_loaders += A + else + A.LateInitialize() + if(INITIALIZE_HINT_QDEL) + qdel(A) + qdeleted = TRUE + else + BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT + + if(!A) //possible harddel + qdeleted = TRUE + else if(!A.initialized) + BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT + + return qdeleted || QDELETED(A) /datum/controller/subsystem/atoms/proc/map_loader_begin() old_initialized = initialized @@ -90,6 +112,7 @@ SUBSYSTEM_DEF(atoms) if(initialized == INITIALIZATION_INNEW_MAPLOAD) InitializeAtoms() old_initialized = SSatoms.old_initialized + BadInitializeCalls = SSatoms.BadInitializeCalls /datum/controller/subsystem/atoms/proc/setupGenetics() var/list/avnums = new /list(DNA_STRUC_ENZYMES_BLOCKS) @@ -109,3 +132,27 @@ SUBSYSTEM_DEF(atoms) else if(B.quality == MINOR_NEGATIVE) GLOB.not_good_mutations |= B CHECK_TICK + +/datum/controller/subsystem/atoms/proc/InitLog() + . = "" + for(var/path in BadInitializeCalls) + . += "Path : [path] \n" + var/fails = BadInitializeCalls[path] + if(fails & BAD_INIT_DIDNT_INIT) + . += "- Didn't call atom/Initialize()\n" + if(fails & BAD_INIT_NO_HINT) + . += "- Didn't return an Initialize hint\n" + if(fails & BAD_INIT_QDEL_BEFORE) + . += "- Qdel'd in New()\n" + if(fails & BAD_INIT_SLEPT) + . += "- Slept during Initialize()\n" + +/datum/controller/subsystem/atoms/Shutdown() + var/initlog = InitLog() + if(initlog) + log_world(initlog) + +#undef BAD_INIT_QDEL_BEFORE +#undef BAD_INIT_DIDNT_INIT +#undef BAD_INIT_SLEPT +#undef BAD_INIT_NO_HINT \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index bfa51a09de7..ed496a9ac30 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -39,20 +39,21 @@ var/do_initialize = SSatoms.initialized if(do_initialize > INITIALIZATION_INSSATOMS) - if(QDELETED(src)) - CRASH("Found new qdeletion in type [type]!") - var/mapload = do_initialize == INITIALIZATION_INNEW_MAPLOAD - args[1] = mapload - if(Initialize(arglist(args)) && mapload) - LAZYADD(SSatoms.late_loaders, src) + args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD + if(SSatoms.InitAtom(src, args)) + //we were deleted + return + + var/list/created = SSatoms.created_atoms + if(created) + created += src //Called after New if the map is being loaded. mapload = TRUE //Called from base of New if the map is being loaded. mapload = FALSE -//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls -//Derivatives must not sleep -//Returning TRUE while mapload is TRUE will cause the object to be initialized again with mapload = FALSE when everything else is done -//(Useful for things that requires turfs to have air). This base may only be called once, however +//This base must be called or derivatives must set initialized to TRUE +//must not sleep //Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE +//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm //Note: the following functions don't call the base for optimization and must copypasta: // /turf/Initialize @@ -75,7 +76,16 @@ if (opacity && isturf(loc)) var/turf/T = loc T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways. + return INITIALIZE_HINT_NORMAL +//called if Initialize returns INITIALIZE_HINT_LATELOAD +//This version shouldn't be called +/atom/proc/LateInitialize() + var/static/list/warned_types = list() + if(!warned_types[type]) + WARNING("Old style LateInitialize behaviour detected in [type]!") + warned_types[type] = TRUE + Initialize(FALSE) /atom/Destroy() if(alternate_appearances) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index f96d6eb8a23..3b82020c608 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -46,7 +46,7 @@ return ..() /atom/movable/Initialize(mapload) - ..() + . = ..() for(var/L in initial_languages) grant_language(L) diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm index 2a23c374447..27a358081d2 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm @@ -135,10 +135,10 @@ /obj/machinery/abductor/console/Initialize(mapload) - if(mapload) - return TRUE //wait for machines list ..() + return INITIALIZE_HINT_LATELOAD +/obj/machinery/abductor/console/LateInitialize() if(!team) return diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index 8fcdc7c4a3a..c10cd5f6c8e 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -19,12 +19,12 @@ /obj/machinery/doorButtons/proc/findObjsByTag() return -/obj/machinery/doorButtons/Initialize(mapload) - if(mapload) - ..() - return TRUE - else - findObjsByTag() +/obj/machinery/doorButtons/Initialize() + ..() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/doorButtons/LateInitialize() + findObjsByTag() /obj/machinery/doorButtons/emag_act(mob/user) if(!emagged) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 4b20f12bf82..a14d345e2f8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -37,7 +37,7 @@ ..() /obj/Initialize() - ..() + . = ..() if (!armor) armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) if(on_blueprints && isturf(loc)) diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index e38bc936e2d..405c2d22253 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -14,18 +14,15 @@ /obj/structure/ladder/Initialize(mapload) - if(!initialized) - GLOB.ladders += src - ..() - if(mapload) - return TRUE - update_link() + GLOB.ladders += src + ..() + return INITIALIZE_HINT_LATELOAD /obj/structure/ladder/Destroy() GLOB.ladders -= src . = ..() -/obj/structure/ladder/proc/update_link() +/obj/structure/ladder/LateInitialize() for(var/obj/structure/ladder/L in GLOB.ladders) if(L.id == id) if(L.height == (height - 1)) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 6c1e2743cd5..a0940eded1f 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -42,6 +42,8 @@ if (opacity) has_opaque_atom = TRUE + + return INITIALIZE_HINT_NORMAL /turf/open/space/attack_ghost(mob/dead/observer/user) if(destination_z) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 10eefc4b14e..1c2d65355ea 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -56,6 +56,7 @@ if (opacity) has_opaque_atom = TRUE + return INITIALIZE_HINT_NORMAL /turf/proc/Initalize_Atmos(times_fired) CalculateAdjacentTurfs() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 607b402f1d4..7d6a49afacf 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -160,7 +160,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug, AVerbsDebug()) /client/proc/clear_dynamic_transit, /client/proc/toggle_medal_disable, /client/proc/view_runtimes, - /client/proc/pump_random_event + /client/proc/pump_random_event, + /client/proc/cmd_display_init_log ) GLOBAL_PROTECT(admin_verbs_possess) GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess,/proc/release)) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 51a80223e0f..5b986e971fa 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -721,6 +721,13 @@ GLOBAL_PROTECT(AdminProcCall) usr << browse(dat, "window=dellog") +/client/proc/cmd_display_init_log() + set category = "Debug" + set name = "Display Initialzie() Log" + set desc = "Displays a list of things that didn't handle Initialize() properly" + + usr << browse(replacetext(SSatoms.InitLog(), "\n", "
"), "window=initlog") + /client/proc/debug_huds(i as num) set category = "Debug" set name = "Debug HUDs" diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 18be292e97f..2648355b10d 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -48,49 +48,49 @@ /obj/machinery/computer/holodeck/Initialize(mapload) - . = mapload //late-initialize, area_copy need turfs to have air - if(!mapload) - ..() + ..() + return INITIALIZE_HINT_LATELOAD - if(ispath(holodeck_type,/area)) - var/list/possible = get_areas(holodeck_type,subtypes = FALSE) - linked = pop(possible) - if(ispath(offline_program,/area)) - var/list/possible = get_areas(offline_program,subtypes = FALSE) - offline_program = pop(possible) - // the following is necessary for power reasons - if(!linked || !offline_program) - log_world("No matching holodeck area found") - qdel(src) - return - var/area/AS = get_area(src) - if(istype(AS,/area/holodeck)) - log_world("### MAPPING ERROR") - log_world("Holodeck computer cannot be in a holodeck.") - log_world("This would cause circular power dependency.") - qdel(src) // todo handle constructed computers - return //l-lewd... - else - linked.linked = src // todo detect multiple/constructed computers +/obj/machinery/computer/holodeck/LateInitialize() + if(ispath(holodeck_type,/area)) + var/list/possible = get_areas(holodeck_type,subtypes = FALSE) + linked = pop(possible) + if(ispath(offline_program,/area)) + var/list/possible = get_areas(offline_program,subtypes = FALSE) + offline_program = pop(possible) + // the following is necessary for power reasons + if(!linked || !offline_program) + log_world("No matching holodeck area found") + qdel(src) + return + var/area/AS = get_area(src) + if(istype(AS,/area/holodeck)) + log_world("### MAPPING ERROR") + log_world("Holodeck computer cannot be in a holodeck.") + log_world("This would cause circular power dependency.") + qdel(src) // todo handle constructed computers + return //l-lewd... + else + linked.linked = src // todo detect multiple/constructed computers - program_cache = list() - emag_programs = list() - for(var/typekey in subtypesof(program_type)) - var/area/holodeck/A = locate(typekey) - if(!A || A == offline_program) - continue - if(A.contents.len == 0) - continue // not loaded - if(A.restricted) - emag_programs += A - else - program_cache += A - if(typekey == init_program) - load_program(A,force=1) - if(random_program && program_cache.len && init_program == null) - load_program(pick(program_cache),force=1) - else if(!program) - load_program(offline_program) + program_cache = list() + emag_programs = list() + for(var/typekey in subtypesof(program_type)) + var/area/holodeck/A = locate(typekey) + if(!A || A == offline_program) + continue + if(A.contents.len == 0) + continue // not loaded + if(A.restricted) + emag_programs += A + else + program_cache += A + if(typekey == init_program) + load_program(A,force=1) + if(random_program && program_cache.len && init_program == null) + load_program(pick(program_cache),force=1) + else if(!program) + load_program(offline_program) /obj/machinery/computer/holodeck/power_change() ..() diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index c3441cc16c9..246bba711f1 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -1,9 +1,6 @@ //Dead mobs can exist whenever. This is needful -/mob/dead/New(loc) - ..() - if(!initialized) - args[1] = FALSE - Initialize(arglist(args)) //EXIST DAMN YOU!!! + +INITIALIZE_IMMEDIATE(/mob/dead) /mob/dead/dust() //ghosts can't be vaporised. return diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index ae11de49739..a5f5b2e1768 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -30,6 +30,7 @@ loc = pick(GLOB.newplayer_start) else loc = locate(1,1,1) + return INITIALIZE_HINT_NORMAL /mob/dead/new_player/proc/new_player_panel() diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 264b6a167d2..68190f5e451 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -212,13 +212,14 @@ /obj/machinery/conveyor_switch/Initialize(mapload, newid) - if(mapload) - return TRUE //need machines list - . = ..() + ..() if(!id) id = newid update() + return INITIALIZE_HINT_LATELOAD //for machines list + +/obj/machinery/conveyor_switch/LateInitialize() conveyors = list() for(var/obj/machinery/conveyor/C in GLOB.machines) if(C.id == id) diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm index 9b1d5e649f2..5013d9d8799 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal-unit.dm @@ -64,17 +64,17 @@ deconstruct() /obj/machinery/disposal/Initialize(mapload) - . = mapload //late-initialize, we need turfs to have air - if(initialized) //will only be run on late mapload initialization - //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it - var/atom/L = loc - var/datum/gas_mixture/env = new - env.copy_from(L.return_air()) - var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1) - air_contents.merge(removed) - trunk_check() - else - ..() + ..() + return INITIALIZE_HINT_LATELOAD //we need turfs to have air + +/obj/machinery/disposal/LateInitialize() + //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it + var/atom/L = loc + var/datum/gas_mixture/env = new + env.copy_from(L.return_air()) + var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1) + air_contents.merge(removed) + trunk_check() /obj/machinery/disposal/attackby(obj/item/I, mob/user, params) add_fingerprint(user) diff --git a/code/modules/shuttle/arrivals.dm b/code/modules/shuttle/arrivals.dm index aa0b9e6f786..ccb8f6b0914 100644 --- a/code/modules/shuttle/arrivals.dm +++ b/code/modules/shuttle/arrivals.dm @@ -22,20 +22,17 @@ var/perma_docked = FALSE //highlander with RESPAWN??? OH GOD!!! /obj/docking_port/mobile/arrivals/Initialize(mapload) - if(mapload) - return TRUE //late initialize to make sure the latejoin list is populated - - preferred_direction = dir - if(SSshuttle.arrivals) WARNING("More than one arrivals docking_port placed on map!") - qdel(src) - return - + return INITIALIZE_HINT_QDEL SSshuttle.arrivals = src . = ..() + preferred_direction = dir + return INITIALIZE_HINT_LATELOAD //for latejoin list + +/obj/docking_port/mobile/arrivals/LateInitialize() areas = list() var/list/new_latejoin = list()