diff --git a/aurorastation.dme b/aurorastation.dme index baaa7e7947c..7b557f77a3b 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -17,9 +17,11 @@ #include "code\names.dm" #include "code\stylesheet.dm" #include "code\__datastructures\stack.dm" +#include "code\__defines\_atoms.dm" #include "code\__defines\_click.dm" #include "code\__defines\_common.dm" #include "code\__defines\_compile_helpers.dm" +#include "code\__defines\_flags.dm" #include "code\__defines\_layers.dm" #include "code\__defines\_macros.dm" #include "code\__defines\_protect.dm" @@ -128,7 +130,9 @@ #include "code\__defines\dcs\flags.dm" #include "code\__defines\dcs\helpers.dm" #include "code\__defines\dcs\signals.dm" -#include "code\__defines\dcs\signals_atom\signals_atom_x_act.dm" +#include "code\__defines\dcs\signals\signals_global.dm" +#include "code\__defines\dcs\signals\signals_atom\signals_atom_main.dm" +#include "code\__defines\dcs\signals\signals_atom\signals_atom_x_act.dm" #include "code\_global_vars\edible.dm" #include "code\_helpers\_global_objects.dm" #include "code\_helpers\_string_lists.dm" @@ -549,6 +553,7 @@ #include "code\game\area\ai_monitored.dm" #include "code\game\area\area_power.dm" #include "code\game\area\areas.dm" +#include "code\game\atom\atoms_initializing_EXPENSIVE.dm" #include "code\game\dna\dna2.dm" #include "code\game\dna\dna2_domutcheck.dm" #include "code\game\dna\dna2_helpers.dm" diff --git a/code/__defines/_atoms.dm b/code/__defines/_atoms.dm new file mode 100644 index 00000000000..abc4d805170 --- /dev/null +++ b/code/__defines/_atoms.dm @@ -0,0 +1,12 @@ +#define BAD_INIT_QDEL_BEFORE 1 +#define BAD_INIT_DIDNT_INIT 2 +#define BAD_INIT_SLEPT 4 +#define BAD_INIT_NO_HINT 8 + +#ifdef PROFILE_MAPLOAD_INIT_ATOM +#define PROFILE_INIT_ATOM_BEGIN(...) var/__profile_stat_time = TICK_USAGE +#define PROFILE_INIT_ATOM_END(atom) mapload_init_times[##atom.type] += TICK_USAGE_TO_MS(__profile_stat_time) +#else +#define PROFILE_INIT_ATOM_BEGIN(...) +#define PROFILE_INIT_ATOM_END(...) +#endif diff --git a/code/__defines/_flags.dm b/code/__defines/_flags.dm new file mode 100644 index 00000000000..88389d00ad4 --- /dev/null +++ b/code/__defines/_flags.dm @@ -0,0 +1,2 @@ +///Whether /atom/Initialize() has already run for the object +#define INITIALIZED_1 (1<<5) diff --git a/code/__defines/dcs/signals/signals_atom/signals_atom_main.dm b/code/__defines/dcs/signals/signals_atom/signals_atom_main.dm new file mode 100644 index 00000000000..d099e721759 --- /dev/null +++ b/code/__defines/dcs/signals/signals_atom/signals_atom_main.dm @@ -0,0 +1,9 @@ +// Main atom signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +// /atom signals +//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization +#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success" +//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization and has a loc +#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON "atom_init_success_on" diff --git a/code/__defines/dcs/signals_atom/signals_atom_x_act.dm b/code/__defines/dcs/signals/signals_atom/signals_atom_x_act.dm similarity index 100% rename from code/__defines/dcs/signals_atom/signals_atom_x_act.dm rename to code/__defines/dcs/signals/signals_atom/signals_atom_x_act.dm diff --git a/code/__defines/dcs/signals/signals_global.dm b/code/__defines/dcs/signals/signals_global.dm new file mode 100644 index 00000000000..85db3a259ec --- /dev/null +++ b/code/__defines/dcs/signals/signals_global.dm @@ -0,0 +1,10 @@ +// Global signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +// global signals +// These are signals which can be listened to by any component on any parent +// start global signals with "!", this used to be necessary but now it's just a formatting choice + +/// called post /obj/item initialize (obj/item/created_item) +#define COMSIG_GLOB_ATOM_AFTER_POST_INIT "!atom_after_post_init" diff --git a/code/__defines/subsystem-defines.dm b/code/__defines/subsystem-defines.dm index 6d836b08675..4743408869d 100644 --- a/code/__defines/subsystem-defines.dm +++ b/code/__defines/subsystem-defines.dm @@ -47,12 +47,15 @@ ///TRUE if the INITIAL SSatoms initialization has finished, aka the atoms are initialized and mapload has finished #define SSATOMS_IS_PROBABLY_DONE (SSatoms.initialized == INITIALIZATION_INNEW_REGULAR) -//type and all subtypes should always call Initialize in New() +///type and all subtypes should always immediately call Initialize in New() #define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\ ..();\ - if(!initialized) {\ + if(!(flags_1 & INITIALIZED_1)) {\ + var/previous_initialized_value = SSatoms.initialized;\ + SSatoms.initialized = INITIALIZATION_INNEW_MAPLOAD;\ args[1] = TRUE;\ - SSatoms.InitAtom(src, args);\ + SSatoms.InitAtom(src, FALSE, args);\ + SSatoms.initialized = previous_initialized_value;\ }\ } @@ -65,11 +68,20 @@ ///New should call Initialize(FALSE) #define INITIALIZATION_INNEW_REGULAR 1 -// Initialize() hints for SSatoms. -#define INITIALIZE_HINT_NORMAL 0 //Nothing happens -#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize -#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom -#define INITIALIZE_HINT_LATEQDEL 3 //Call qdel on the atom instead of LateInitialize +///Nothing happens. +#define INITIALIZE_HINT_NORMAL 0 + +/** + * call LateInitialize at the end of all atom Initalization + * + * The item will be added to the late_loaders list, this is iterated over after + * initalization of subsystems is complete and calls LateInitalize on the atom + * see [this file for the LateIntialize proc](atom.html#proc/LateInitialize) + */ +#define INITIALIZE_HINT_LATELOAD 1 + +///Call qdel on the atom after intialization +#define INITIALIZE_HINT_QDEL 2 // -- SSoverlays -- diff --git a/code/_helpers/atoms.dm b/code/_helpers/atoms.dm index 7e1de4e88b0..309aa36db11 100644 --- a/code/_helpers/atoms.dm +++ b/code/_helpers/atoms.dm @@ -1,3 +1,13 @@ +///Returns the src and all recursive contents as a list. +/atom/proc/get_all_contents(ignore_flag_1) + . = list(src) + var/i = 0 + while(i < length(.)) + var/atom/checked_atom = .[++i] + if(checked_atom.flags_1 & ignore_flag_1) + continue + . += checked_atom.contents + ///similar function to range(), but with no limitations on the distance; will search spiralling outwards from the center ///NOT Z-Level aware /proc/spiral_range(dist = 0, center = usr, orange = FALSE) diff --git a/code/_helpers/logging/_logging.dm b/code/_helpers/logging/_logging.dm index 6333ff56d0f..4e334b04a58 100644 --- a/code/_helpers/logging/_logging.dm +++ b/code/_helpers/logging/_logging.dm @@ -30,10 +30,25 @@ world.log << "## WARNING: [msg][log_end]" log_world("WARNING: [msg]") -//print a testing-mode debug message to world.log -/proc/testing(msg) - world.log << "## TESTING: [msg][log_end]" - log_world("TESTING: [msg]") +//print a testing-mode debug message to world.log and world +#ifdef TESTING +#define testing(msg) log_world("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]") + +//When we port GLOB ... +//GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) + +// we don't really check if a word or name is used twice, be aware of that +#define testing_profile_start(NAME, LIST) LIST[NAME] = world.timeofday +#define testing_profile_current(NAME, LIST) round((world.timeofday - LIST[NAME])/10,0.1) +#define testing_profile_output(NAME, LIST) testing("[LIST["_PROFILE_NAME"]] profile of [NAME] is [testing_profile_current(NAME,LIST)]s") +#define testing_profile_output_all(LIST) { for(var/_NAME in LIST) { testing_profile_current(,_NAME,LIST); }; }; +#else +#define testing(msg) +#define testing_profile_start(NAME, LIST) +#define testing_profile_current(NAME, LIST) +#define testing_profile_output(NAME, LIST) +#define testing_profile_output_all(LIST) +#endif /proc/game_log(category, text) WRITE_LOG(diary, "[game_id] [category]: [text][log_end]") diff --git a/code/_helpers/mouse.dm b/code/_helpers/mouse.dm index a14ed4b22a4..7656c55c277 100644 --- a/code/_helpers/mouse.dm +++ b/code/_helpers/mouse.dm @@ -9,8 +9,5 @@ . = params2list(params) -#ifdef TESTING - testing("X: [.["icon-x"]], Y: [.["icon-y"]]") -#endif return list("icon-x" = Clamp(text2num(.["icon-x"]), 0, lim_x), "icon-y" = Clamp(text2num(.["icon-y"]), 0, lim_y)) diff --git a/code/_helpers/spatial_info.dm b/code/_helpers/spatial_info.dm index 484cb0fd717..a3834c40cb6 100644 --- a/code/_helpers/spatial_info.dm +++ b/code/_helpers/spatial_info.dm @@ -31,7 +31,11 @@ /mob/abstract/oranges_ear/Initialize(mapload) SHOULD_CALL_PARENT(FALSE) - initialized = TRUE + + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + return INITIALIZE_HINT_NORMAL /mob/abstract/oranges_ear/Destroy(force) diff --git a/code/controllers/master/subsystem.dm b/code/controllers/master/subsystem.dm index 4ff83feb408..12a14b1384e 100644 --- a/code/controllers/master/subsystem.dm +++ b/code/controllers/master/subsystem.dm @@ -12,6 +12,9 @@ /// Which stage does this subsystem init at. Earlier stages can fire while later stages init. var/init_stage = INITSTAGE_MAIN + /// This var is set to TRUE after the subsystem has been initialized. + var/initialized = FALSE + /// Levels of the game that the SS can fire. See __defines/subsystem_priority.dm var/runlevels = RUNLEVELS_DEFAULT diff --git a/code/controllers/subsystems/event.dm b/code/controllers/subsystems/event.dm index df4f90aa11a..3e3db59b521 100644 --- a/code/controllers/subsystems/event.dm +++ b/code/controllers/subsystems/event.dm @@ -23,7 +23,7 @@ SUBSYSTEM_DEF(events) var/datum/event_meta/new_event = new - var/initialized = FALSE + initialized = FALSE /datum/controller/subsystem/events/Initialize() allEvents = subtypesof(/datum/event) diff --git a/code/controllers/subsystems/icon_smooth.dm b/code/controllers/subsystems/icon_smooth.dm index 65ae77cd671..725f28da2f4 100644 --- a/code/controllers/subsystems/icon_smooth.dm +++ b/code/controllers/subsystems/icon_smooth.dm @@ -55,7 +55,7 @@ SUBSYSTEM_DEF(icon_smooth) if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED)) continue - if(smoothing_atom.initialized && !(smoothing_atom.icon_update_queued)) + if((smoothing_atom.flags_1 & INITIALIZED_1) && !(smoothing_atom.icon_update_queued)) smooth_icon(smoothing_atom) else deferred += smoothing_atom diff --git a/code/controllers/subsystems/icon_updates.dm b/code/controllers/subsystems/icon_updates.dm index c36e54262e9..62976d6e001 100644 --- a/code/controllers/subsystems/icon_updates.dm +++ b/code/controllers/subsystems/icon_updates.dm @@ -33,7 +33,7 @@ SUBSYSTEM_DEF(icon_update) var/list/argv = icon_update_queue_cache[A] icon_update_queue_cache.len-- - if(A.initialized) + if(A.flags_1 & INITIALIZED_1) A.icon_update_queued = FALSE //Do not target qdeleted atoms diff --git a/code/controllers/subsystems/initialization/atoms.dm b/code/controllers/subsystems/initialization/atoms.dm index 8e17f997cb4..5be75f4c119 100644 --- a/code/controllers/subsystems/initialization/atoms.dm +++ b/code/controllers/subsystems/initialization/atoms.dm @@ -1,10 +1,4 @@ #define SUBSYSTEM_INIT_SOURCE "subsystem init" - -#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" init_order = SS_INIT_ATOMS @@ -15,159 +9,106 @@ SUBSYSTEM_DEF(atoms) var/list/initialized_state = list() var/base_initialized - var/initialized = INITIALIZATION_INSSATOMS - var/old_initialized - - var/list/late_misc_firers // this is a list of things that fire when late misc init is called - - var/list/late_loaders - var/list/created_atoms - var/list/late_qdel + var/list/late_loaders = list() var/list/BadInitializeCalls = list() + ///initAtom() adds the atom its creating to this list iff InitializeAtoms() has been given a list to populate as an argument + var/list/created_atoms + + /// Atoms that will be deleted once the subsystem is initialized + var/list/queued_deletions = list() + + var/init_start_time + + #ifdef PROFILE_MAPLOAD_INIT_ATOM + var/list/mapload_init_times = list() + #endif + + initialized = INITIALIZATION_INSSATOMS + /datum/controller/subsystem/atoms/Initialize(timeofday) + init_start_time = world.time + initialized = INITIALIZATION_INNEW_MAPLOAD InitializeAtoms() initialized = INITIALIZATION_INNEW_REGULAR + return ..() -/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms) +/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms, list/atoms_to_return) if(initialized == INITIALIZATION_INSSATOMS) return set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, SUBSYSTEM_INIT_SOURCE) - LAZYINITLIST(late_loaders) - LAZYINITLIST(late_qdel) - - var/count - var/list/mapload_arg = list(TRUE) - if(atoms) - created_atoms = list() - count = atoms.len - for(var/I in 1 to atoms.len) - var/atom/A = atoms[I] - InitAtom(A, mapload_arg) - CHECK_TICK - else - count = 0 - for(var/atom/A as anything in world) - if(!A.initialized) - InitAtom(A, mapload_arg) - ++count - CHECK_TICK - - admin_notice(SPAN_DANGER("Initialized [count] atoms."), R_DEBUG) - log_subsystem("atoms", "Initialized [count] atoms.") - + // This may look a bit odd, but if the actual atom creation runtimes for some reason, we absolutely need to set initialized BACK + CreateAtoms(atoms, atoms_to_return) clear_tracked_initalize(SUBSYSTEM_INIT_SOURCE) if(late_loaders.len) for(var/I in 1 to late_loaders.len) var/atom/A = late_loaders[I] + //I hate that we need this if(QDELETED(A)) continue A.LateInitialize() - admin_notice(SPAN_DANGER("Late-initialized [late_loaders.len] atoms."), R_DEBUG) - log_subsystem("atoms", "Late initialized [late_loaders.len] atoms") + testing("Late initialized [late_loaders.len] atoms") late_loaders.Cut() - if(late_qdel.len) - var/num_qdels = late_qdel.len - for(var/thing in late_qdel) - qdel(thing) + if (created_atoms) + atoms_to_return += created_atoms + created_atoms = null - admin_notice(SPAN_DANGER("Late-qdeleted [num_qdels] atoms."), R_DEBUG) - log_subsystem("atoms", "Late qdeleted [num_qdels] atoms.") + for (var/queued_deletion in queued_deletions) + qdel(queued_deletion) - late_qdel.Cut() + testing("[queued_deletions.len] atoms were queued for deletion.") + queued_deletions.Cut() + + #ifdef PROFILE_MAPLOAD_INIT_ATOM + rustg_file_write(json_encode(mapload_init_times), "[GLOB.log_directory]/init_times.json") + #endif + +/// Actually creates the list of atoms. Exists soley so a runtime in the creation logic doesn't cause initalized to totally break +/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null) + if (atoms_to_return) + LAZYINITLIST(created_atoms) + + #ifdef TESTING + var/count + #endif + + var/list/mapload_arg = list(TRUE) if(atoms) - . = created_atoms + atoms - created_atoms = null - // Note this doesn't actually do anything because we didn't finish porting TG init :^) + #ifdef TESTING + count = atoms.len + #endif -/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 + for(var/I in 1 to atoms.len) + var/atom/A = atoms[I] + if(!(A.flags_1 & INITIALIZED_1)) + CHECK_TICK + PROFILE_INIT_ATOM_BEGIN() + InitAtom(A, TRUE, mapload_arg) + PROFILE_INIT_ATOM_END(A) + else + #ifdef TESTING + count = 0 + #endif - var/start_tick = world.time + for(var/atom/A as anything in world) + if(!(A.flags_1 & INITIALIZED_1)) + PROFILE_INIT_ATOM_BEGIN() + InitAtom(A, FALSE, mapload_arg) + PROFILE_INIT_ATOM_END(A) + #ifdef TESTING + ++count + #endif + CHECK_TICK - var/result = A.Initialize(arglist(arguments)) - - if(start_tick != world.time) - BadInitializeCalls[the_type] |= BAD_INIT_SLEPT - - 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) - return TRUE - if(INITIALIZE_HINT_LATEQDEL) - if(arguments[1]) //mapload - late_qdel += A - else - qdel(A) - return TRUE - else - BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT - - if(!A) //possible harddel - return TRUE - else if(!A.initialized) - BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT - - return QDELETED(A) - -/datum/controller/subsystem/atoms/proc/ForceInitializeContents(atom/A) - var/list/mload_args = list(TRUE) - var/loaded = 0 - - set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, SUBSYSTEM_INIT_SOURCE+"- ForceInitializeContents: [text_ref(A)]") - - for (var/thing in A) - var/atom/movable/AM = thing - if (!AM.initialized) - InitAtom(AM, mload_args) - ++loaded - - clear_tracked_initalize(SUBSYSTEM_INIT_SOURCE+"- ForceInitializeContents: [text_ref(A)]") - - LOG_DEBUG("atoms: force-loaded [loaded] out of [A.contents.len] atoms in [A].") - -/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) - world.log << initlog*/ - -/datum/controller/subsystem/atoms/Recover() - initialized = SSatoms.initialized - if(initialized == INITIALIZATION_INNEW_MAPLOAD) - InitializeAtoms() - initialized_state = SSatoms.initialized_state - BadInitializeCalls = SSatoms.BadInitializeCalls + testing("Initialized [count] atoms") /datum/controller/subsystem/atoms/proc/map_loader_begin(source) set_tracked_initalized(INITIALIZATION_INSSATOMS, source) @@ -201,4 +142,40 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/proc/initializing_something() return length(initialized_state) > 1 +/datum/controller/subsystem/atoms/Recover() + initialized = SSatoms.initialized + if(initialized == INITIALIZATION_INNEW_MAPLOAD) + InitializeAtoms() + initialized_state = SSatoms.initialized_state + BadInitializeCalls = SSatoms.BadInitializeCalls + +/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" + +/// Prepares an atom to be deleted once the atoms SS is initialized. +/datum/controller/subsystem/atoms/proc/prepare_deletion(atom/target) + if (initialized == INITIALIZATION_INNEW_REGULAR) + // Atoms SS has already completed, just kill it now. + qdel(target) + else + queued_deletions += WEAKREF(target) + +/datum/controller/subsystem/atoms/Shutdown() + var/initlog = InitLog() + if(initlog) + world.log << initlog + //text2file(initlog, "[log_directory]/initialize.log") + + #undef SUBSYSTEM_INIT_SOURCE diff --git a/code/controllers/subsystems/initialization/misc_late.dm b/code/controllers/subsystems/initialization/misc_late.dm index 18963fcd05d..aff1bdc0823 100644 --- a/code/controllers/subsystems/initialization/misc_late.dm +++ b/code/controllers/subsystems/initialization/misc_late.dm @@ -27,9 +27,9 @@ SUBSYSTEM_DEF(misc_late) populate_code_phrases() // this covers mapped in drone fabs - for(var/atom/thing as anything in SSatoms.late_misc_firers) + for(var/atom/thing as anything in SSatoms.late_loaders) thing.do_late_fire() - LAZYREMOVE(SSatoms.late_misc_firers, thing) + LAZYREMOVE(SSatoms.late_loaders, thing) if (config.use_forumuser_api) update_admins_from_api(TRUE) diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index b6a7e9cb0d9..ac470f9b8bc 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -11,7 +11,7 @@ SUBSYSTEM_DEF(overlays) var/idex = 1 var/list/overlay_icon_state_caches = list() var/list/overlay_icon_cache = list() - var/initialized = FALSE + initialized = FALSE /datum/controller/subsystem/overlays/stat_entry(msg) msg = "Ov:[processing.len - (idex - 1)]" diff --git a/code/game/atom/atoms_initializing_EXPENSIVE.dm b/code/game/atom/atoms_initializing_EXPENSIVE.dm new file mode 100644 index 00000000000..5e2345032fd --- /dev/null +++ b/code/game/atom/atoms_initializing_EXPENSIVE.dm @@ -0,0 +1,164 @@ +/// Init this specific atom +/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, from_template = FALSE, list/arguments) + var/the_type = A.type + + if(QDELING(A)) + // Check init_start_time to not worry about atoms created before the atoms SS that are cleaned up before this + if (A.gcDestroyed > init_start_time) + BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE + return TRUE + + // This is handled and battle tested by dreamchecker. Limit to UNIT_TESTS just in case that ever fails. + #ifdef UNIT_TEST + var/start_tick = world.time + #endif + + var/result = A.Initialize(arglist(arguments)) + + #ifdef UNIT_TEST + if(start_tick != world.time) + BadInitializeCalls[the_type] |= BAD_INIT_SLEPT + #endif + + 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.flags_1 & INITIALIZED_1)) + BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT + else + SEND_SIGNAL(A, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_ATOM_AFTER_POST_INIT, A) + var/atom/location = A.loc + if(location) + /// Sends a signal that the new atom `src`, has been created at `loc` + SEND_SIGNAL(location, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, A, arguments[1]) + if(created_atoms && from_template && ispath(the_type, /atom/movable))//we only want to populate the list with movables + created_atoms += A.get_all_contents() + + return qdeleted || QDELING(A) + +/** + * Called when an atom is created in byond (built in engine proc) + * + * Not a lot happens here in SS13 code, as we offload most of the work to the + * [Intialization][/atom/proc/Initialize] proc, mostly we run the preloader + * if the preloader is being used and then call [InitAtom][/datum/controller/subsystem/atoms/proc/InitAtom] of which the ultimate + * result is that the Intialize proc is called. + * + */ +/atom/New(loc, ...) + // For the DMM Suite. + if(use_preloader && (type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New() + _preloader.load(src) + + //. = ..() //uncomment if you are dumb enough to add a /datum/New() proc + + var/do_initialize = SSatoms.initialized + if(do_initialize != INITIALIZATION_INSSATOMS) + args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD + if(SSatoms.InitAtom(src, FALSE, args)) + //we were deleted + return + +/** + * The primary method that objects are setup in SS13 with + * + * we don't use New as we have better control over when this is called and we can choose + * to delay calls or hook other logic in and so forth + * + * During roundstart map parsing, atoms are queued for intialization in the base atom/New(), + * After the map has loaded, then Initalize is called on all atoms one by one. NB: this + * is also true for loading map templates as well, so they don't Initalize until all objects + * in the map file are parsed and present in the world + * + * If you're creating an object at any point after SSInit has run then this proc will be + * immediately be called from New. + * + * mapload: This parameter is true if the atom being loaded is either being intialized during + * the Atom subsystem intialization, or if the atom is being loaded from the map template. + * If the item is being created at runtime any time after the Atom subsystem is intialized then + * it's false. + * + * The mapload argument occupies the same position as loc when Initialize() is called by New(). + * loc will no longer be needed after it passed New(), and thus it is being overwritten + * with mapload at the end of atom/New() before this proc (atom/Initialize()) is called. + * + * You must always call the parent of this proc, otherwise failures will occur as the item + * will not be seen as initalized (this can lead to all sorts of strange behaviour, like + * the item being completely unclickable) + * + * You must not sleep in this proc, or any subprocs + * + * Any parameters from new are passed through (excluding loc), naturally if you're loading from a map + * there are no other arguments + * + * Must return an [initialization hint][INITIALIZE_HINT_NORMAL] or a runtime will occur. + * + * Note: the following functions don't call the base for optimization and must copypasta handling: + * * [/turf/proc/Initialize] + * * [/turf/open/space/proc/Initialize] + * + * NOTE: This desc is of TG's implementation, it might not be reflective of the current one we have here + */ +/atom/proc/Initialize(mapload, ...) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + + if(LAZYLEN(reagents_to_add)) + if(!reagents) + create_reagents(0) + for(var/v in reagents_to_add) + reagents.maximum_volume += max(LAZYACCESS(reagents_to_add, v) - REAGENTS_FREE_SPACE(reagents), 0) + reagents.add_reagent(v, LAZYACCESS(reagents_to_add, v), LAZYACCESS(reagent_data, v)) + + if (light_power && light_range) + update_light() + + 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. + + #ifdef AO_USE_LIGHTING_OPACITY + if (!mapload) + T.regenerate_ao() + #endif + + if (update_icon_on_init) + SSicon_update.add_to_queue(src) + + return INITIALIZE_HINT_NORMAL + +/** + * Late Intialization, for code that should run after all atoms have run Intialization + * + * To have your LateIntialize proc be called, your atoms [Initalization][/atom/proc/Initialize] + * proc must return the hint + * [INITIALIZE_HINT_LATELOAD] otherwise it will never be called. + * + * useful for doing things like finding other machines on GLOB.machines because you can guarantee + * that all atoms will actually exist in the "WORLD" at this time and that all their Intialization + * code has been run + */ +/atom/proc/LateInitialize() + set waitfor = FALSE + + //You can override this in your inheritance if you *really* need to, but probably shouldn't + SHOULD_NOT_SLEEP(TRUE) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d7e39c47750..c15401e1561 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -729,7 +729,7 @@ if(SSticker.current_state == GAME_STATE_PLAYING) do_late_fire() return - LAZYADD(SSatoms.late_misc_firers, src) + LAZYADD(SSatoms.late_loaders, src) /atom/proc/do_late_fire() return diff --git a/code/game/atoms_init.dm b/code/game/atoms_init.dm index 6da4bb6230a..2afbd59d74d 100644 --- a/code/game/atoms_init.dm +++ b/code/game/atoms_init.dm @@ -1,81 +1,9 @@ /atom - ///Whether /atom/Initialize() has already run for the object - var/initialized = FALSE + ///First atom flags var + var/flags_1 = NONE + var/update_icon_on_init // Default to 'no'. -/atom/New(loc, ...) - // For the DMM Suite. - if(use_preloader && (type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New() - _preloader.load(src) - - //. = ..() //uncomment if you are dumb enough to add a /datum/New() proc - - var/do_initialize = SSatoms.initialized - if(do_initialize > INITIALIZATION_INSSATOMS) - 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 - -/atom/proc/Initialize(mapload, ...) - SHOULD_CALL_PARENT(TRUE) - SHOULD_NOT_SLEEP(TRUE) - - if(initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") - initialized = TRUE - - if(LAZYLEN(reagents_to_add)) - if(!reagents) - create_reagents(0) - for(var/v in reagents_to_add) - reagents.maximum_volume += max(LAZYACCESS(reagents_to_add, v) - REAGENTS_FREE_SPACE(reagents), 0) - reagents.add_reagent(v, LAZYACCESS(reagents_to_add, v), LAZYACCESS(reagent_data, v)) - - if (light_power && light_range) - update_light() - - 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. - - #ifdef AO_USE_LIGHTING_OPACITY - if (!mapload) - T.regenerate_ao() - #endif - - if (update_icon_on_init) - SSicon_update.add_to_queue(src) - - return INITIALIZE_HINT_NORMAL - -/** - * Late Intialization, for code that should run after all atoms have run Intialization - * - * To have your LateIntialize proc be called, your atoms [Initalization][/atom/proc/Initialize] - * proc must return the hint - * [INITIALIZE_HINT_LATELOAD] otherwise it will never be called. - * - * useful for doing things like finding other machines because you can guarantee - * that all atoms will actually exist in the "WORLD" at this time and that all their Intialization - * code has been run - */ -/atom/proc/LateInitialize() - set waitfor = FALSE - - //You can override this in your inheritance if you *really* need to, but probably shouldn't - SHOULD_NOT_SLEEP(TRUE) - - 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(force = FALSE) if (reagents) QDEL_NULL(reagents) diff --git a/code/game/objects/effects/decals/Cleanable/fuel.dm b/code/game/objects/effects/decals/Cleanable/fuel.dm index 7b109d81633..2dad245892f 100644 --- a/code/game/objects/effects/decals/Cleanable/fuel.dm +++ b/code/game/objects/effects/decals/Cleanable/fuel.dm @@ -122,6 +122,11 @@ /obj/effect/decal/cleanable/foam/Initialize(mapload, amt = 1, nologs = 0) SHOULD_CALL_PARENT(FALSE) + + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + src.amount = amt var/has_spread = 0 @@ -133,8 +138,6 @@ has_spread = 1 break - initialized = TRUE - if(!has_spread) Spread() QDEL_IN(src, 2 MINUTES) diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index b0ddc90017a..b2db60becf8 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -24,6 +24,10 @@ if(!current_map.use_overmap) return ..() + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + var/turf/T = get_turf(src) var/obj/effect/overmap/visitable/V = map_sectors["[T.z]"] if(istype(V) && V.comms_support) @@ -38,7 +42,6 @@ if(use_common) channels += list(CHANNEL_COMMON = TRUE) - initialized = TRUE return INITIALIZE_HINT_NORMAL /obj/item/device/encryptionkey/ship/common diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index b09cad09c23..70cfcbe979c 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -452,9 +452,12 @@ pixel_x = 8; /obj/item/device/radio/intercom/broadcasting/Initialize() SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + set_broadcasting(TRUE) - initialized = TRUE return INITIALIZE_HINT_NORMAL /obj/item/device/radio/intercom/locked diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index 3588189c06f..37660033c98 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -53,7 +53,10 @@ imprisoned = temporarymob if(health == 0) //meaning if the statue didn't find a valid target - initialized = TRUE + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + return INITIALIZE_HINT_QDEL START_PROCESSING(SSprocessing, src) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 5e2ad1207be..248fa928e17 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -27,16 +27,15 @@ /turf/space/Initialize() SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + if(use_space_appearance) appearance = SSskybox.space_appearance_cache[(((x + y) ^ ~(x * y) + z) % 25) + 1] if(config.starlight && use_starlight && lighting_overlays_initialized) update_starlight() - if (initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") - - initialized = TRUE - for(var/atom/movable/AM as mob|obj in src) src.Entered(AM, AM.loc) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 481eed3c7e1..4f9907a18f7 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -59,10 +59,9 @@ /turf/Initialize(mapload, ...) SHOULD_CALL_PARENT(FALSE) - if (initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") - - initialized = TRUE + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 for(var/atom/movable/AM as mob|obj in src) Entered(AM, src) diff --git a/code/game/turfs/unsimulated/floor.dm b/code/game/turfs/unsimulated/floor.dm index c5b70ee3482..7f983928d73 100644 --- a/code/game/turfs/unsimulated/floor.dm +++ b/code/game/turfs/unsimulated/floor.dm @@ -50,8 +50,11 @@ /turf/unsimulated/mask/Initialize() SHOULD_CALL_PARENT(FALSE) - initialized = TRUE - return + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + + return INITIALIZE_HINT_NORMAL /turf/unsimulated/chasm_mask/New() return diff --git a/code/modules/effects/map_effects/window_spawner.dm b/code/modules/effects/map_effects/window_spawner.dm index cc43d960ea5..c51d0ce281d 100644 --- a/code/modules/effects/map_effects/window_spawner.dm +++ b/code/modules/effects/map_effects/window_spawner.dm @@ -34,7 +34,7 @@ activate() - return INITIALIZE_HINT_LATEQDEL + return INITIALIZE_HINT_QDEL /obj/effect/map_effect/window_spawner/proc/activate() if(activated) diff --git a/code/modules/effects/maze_generation/maze_generator.dm b/code/modules/effects/maze_generation/maze_generator.dm index 7b61bde2e63..f9fba0f18fb 100644 --- a/code/modules/effects/maze_generation/maze_generator.dm +++ b/code/modules/effects/maze_generation/maze_generator.dm @@ -51,7 +51,7 @@ do { \ run_generator() /obj/effect/mazegen/generator/Destroy() - LAZYREMOVE(SSatoms.late_misc_firers, src) + LAZYREMOVE(SSatoms.late_loaders, src) return ..() // "Push" a turf to the working "stack" diff --git a/code/modules/heavy_vehicle/mecha_part_spawners.dm b/code/modules/heavy_vehicle/mecha_part_spawners.dm index 7d7be896a55..efea59184b8 100644 --- a/code/modules/heavy_vehicle/mecha_part_spawners.dm +++ b/code/modules/heavy_vehicle/mecha_part_spawners.dm @@ -8,7 +8,7 @@ ..() parts_to_spawn = get_parts_to_spawn() spawn_parts() - return INITIALIZE_HINT_LATEQDEL + return INITIALIZE_HINT_QDEL /obj/effect/map_effect/mecha_part_spawner/proc/get_parts_to_spawn() return list() diff --git a/code/modules/maps/map_template.dm b/code/modules/maps/map_template.dm index 6408aa8b6eb..66b90f68ba2 100644 --- a/code/modules/maps/map_template.dm +++ b/code/modules/maps/map_template.dm @@ -121,7 +121,7 @@ apcs += A if(isnull(A)) atoms -= A - if(A.initialized) + if(A.flags_1 & INITIALIZED_1) atoms -= A var/notsuspended diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 97677a0727b..6b99a376df7 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -64,14 +64,13 @@ var/list/mineral_can_smooth_with = list( // Copypaste parent call for performance. /turf/simulated/mineral/Initialize(mapload) - if(initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 if(icon != actual_icon) icon = actual_icon - initialized = TRUE - if(isStationLevel(z)) station_turfs += src @@ -184,14 +183,13 @@ var/list/mineral_can_smooth_with = list( /turf/unsimulated/mineral/asteroid/Initialize(mapload) SHOULD_CALL_PARENT(FALSE) - if(initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 if(icon != actual_icon) icon = actual_icon - initialized = TRUE - if(isStationLevel(z)) station_turfs += src @@ -652,9 +650,9 @@ var/list/asteroid_floor_smooth = list( // Copypaste parent for performance. /turf/unsimulated/floor/asteroid/Initialize(mapload) - if(initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") - initialized = TRUE + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 if(icon != base_icon) // Setting icon is an appearance change, so avoid it if we can. icon = base_icon diff --git a/code/modules/mob/abstract/new_player/preferences_setup.dm b/code/modules/mob/abstract/new_player/preferences_setup.dm index 444544f0d31..e98e1d84a53 100644 --- a/code/modules/mob/abstract/new_player/preferences_setup.dm +++ b/code/modules/mob/abstract/new_player/preferences_setup.dm @@ -227,7 +227,7 @@ SSjobs.EquipCustomDeferred(mannequin, src, leftovers, used_slots) if (!SSATOMS_IS_PROBABLY_DONE) - SSatoms.ForceInitializeContents(mannequin) + SSatoms.CreateAtoms(list(mannequin)) mannequin.regenerate_icons() else mannequin.update_icon() diff --git a/code/modules/mob/living/announcer.dm b/code/modules/mob/living/announcer.dm index c066a1d93c6..742273d1c33 100755 --- a/code/modules/mob/living/announcer.dm +++ b/code/modules/mob/living/announcer.dm @@ -27,9 +27,10 @@ /mob/living/announcer/Initialize() // we specifically do not call parent Initialize here because this mob should not need it and its point is to be lightweight SHOULD_CALL_PARENT(FALSE) - if(initialized) - crash_with("Warning: [src]([type]) initialized multiple times!") - initialized = TRUE + + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 for(var/K in all_languages) add_language(K) diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index 4a05d9707ca..ac440c45621 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -2,11 +2,13 @@ real_name = "Test Dummy" status_flags = GODMODE|CANPUSH + /mob/living/carbon/human/dummy/mannequin mob_thinks = FALSE INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy/mannequin) + /mob/living/carbon/human/dummy/mannequin/Initialize() . = ..() mob_list -= src diff --git a/code/modules/mob/living/carbon/slime/items.dm b/code/modules/mob/living/carbon/slime/items.dm index f3be138bb06..a746f8d7f50 100644 --- a/code/modules/mob/living/carbon/slime/items.dm +++ b/code/modules/mob/living/carbon/slime/items.dm @@ -137,9 +137,6 @@ filling.color = COLOR_PINK add_overlay(filling) - initialized = TRUE - return INITIALIZE_HINT_NORMAL - /obj/item/docility_serum/attack(mob/living/carbon/slime/M as mob, mob/user as mob) if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime. to_chat(user, SPAN_WARNING("The docility serum only works on slimes!")) @@ -183,9 +180,6 @@ filling.color = COLOR_PALE_PINK add_overlay(filling) - initialized = TRUE - return INITIALIZE_HINT_NORMAL - /obj/item/advanced_docility_serum/attack(mob/living/carbon/slime/M as mob, mob/user as mob) if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime. to_chat(user, SPAN_WARNING("The docility serum only works on slimes!")) @@ -226,11 +220,14 @@ /obj/item/slimesteroid/Initialize() // Better than hardsprited in stuff. SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + var/mutable_appearance/filling = mutable_appearance(icon, "[icon_state]-100") filling.color = COLOR_GREEN add_overlay(filling) - initialized = TRUE return INITIALIZE_HINT_NORMAL /obj/item/slimesteroid/attack(mob/living/carbon/slime/M as mob, mob/user as mob) @@ -262,11 +259,14 @@ /obj/item/extract_enhancer/Initialize() // Better than hardsprited in stuff. SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + var/mutable_appearance/filling = mutable_appearance(icon, "[icon_state]-100") filling.color = COLOR_BLUE add_overlay(filling) - initialized = TRUE return INITIALIZE_HINT_NORMAL /obj/effect/golemrune diff --git a/code/modules/mob/living/simple_animal/corpse.dm b/code/modules/mob/living/simple_animal/corpse.dm index ca9f0771800..6215aade1f2 100644 --- a/code/modules/mob/living/simple_animal/corpse.dm +++ b/code/modules/mob/living/simple_animal/corpse.dm @@ -31,9 +31,6 @@ . = ..() createCorpse() - initialized = TRUE - return INITIALIZE_HINT_NORMAL - /obj/effect/landmark/mobcorpse/proc/createCorpse() //Creates a mob and checks for gear in each slot before attempting to equip it. var/mob/living/carbon/human/M = new /mob/living/carbon/human (src.loc) M.real_name = src.name diff --git a/code/modules/multiz/zmimic/mimic_movable.dm b/code/modules/multiz/zmimic/mimic_movable.dm index d22fdfd37b2..bf4da8e527c 100644 --- a/code/modules/multiz/zmimic/mimic_movable.dm +++ b/code/modules/multiz/zmimic/mimic_movable.dm @@ -151,8 +151,8 @@ var/original_z var/override_depth -/atom/movable/openspace/mimic/New() - initialized = TRUE +/atom/movable/openspace/mimic/Initialize(mapload, ...) + . = ..() SSzcopy.openspace_overlays += 1 /atom/movable/openspace/mimic/Destroy() diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 701d0b1b1f5..5433b5afe6f 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -47,11 +47,11 @@ var/force_skintone = FALSE // If true, icon generation will skip is-robotic checks. Used for synthskin limbs. var/list/species_restricted //used by augments and biomods to see what species can have this augment -/obj/item/organ/New(loc, ...) - ..() - if (!initialized && istype(loc, /mob/living/carbon/human/dummy/mannequin)) - args[1] = TRUE - SSatoms.InitAtom(src, args) +INITIALIZE_IMMEDIATE(/obj/item/organ) + +/obj/item/organ/Initialize(mapload, internal) + . = ..() + /obj/item/organ/Destroy() STOP_PROCESSING(SSprocessing, src) diff --git a/code/modules/telesci/gps.dm b/code/modules/telesci/gps.dm index 2f98429fa2e..793dd6d9f0d 100644 --- a/code/modules/telesci/gps.dm +++ b/code/modules/telesci/gps.dm @@ -322,6 +322,10 @@ var/list/GPS_list = list() /obj/item/device/gps/stationary/Initialize() SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + compass = new(src) update_position() @@ -352,7 +356,6 @@ var/list/GPS_list = list() START_PROCESSING(SSprocessing, src) - initialized = TRUE return INITIALIZE_HINT_NORMAL /obj/item/device/gps/stationary/attack_hand() // Don't let users pick it up. diff --git a/html/changelogs/fluffyghost-ssatomupdate.yml b/html/changelogs/fluffyghost-ssatomupdate.yml new file mode 100644 index 00000000000..87071c2cbfe --- /dev/null +++ b/html/changelogs/fluffyghost-ssatomupdate.yml @@ -0,0 +1,52 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - backend: "Updated SSAtoms to TG's version." + - backend: "Added signals for initialization, repathed old signal_athom_x_act.dm to its updated home." + - backend: "Moved /atom initialization related procs in atom/atoms_initializing_EXPENSIVE.dm as per TG." + - backend: "Updated INITIALIZE_IMMEDIATE to work with the new subsystem." + - backend: "Adapted various procs and other subsystems to work with the new SSAtoms." + - backend: "Reordered some procs to set the initialization flag at the start, as that is the supposed behavior." + - backend: "Transformed the testing() proc to a macro, as per TG." + - backend: "Cleaned up some initializations a bit." + - backend: "Flagged organs for immediate initialization." + - backend: "Initialized variable is now flags_1, as per TG." + - backend: "The Initialized variable is now global for every subsytem." + - backend: "Various reordering and flags/defines additions."