diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index cf23deb2de..e4a3c243e2 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -1,4 +1,12 @@ +#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 + // SS runlevels #define RUNLEVEL_INIT 0 // "Initialize Only" - Used for subsystems that should never be fired (Should also have SS_NO_FIRE set) @@ -15,6 +23,8 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G // Subsystem init_order, from highest priority to lowest priority // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. +#define INIT_ORDER_DECALS 16 +#define INIT_ORDER_ATOMS 15 #define INIT_ORDER_MACHINES 10 #define INIT_ORDER_LIGHTING 0 #define INIT_ORDER_AIR -1 diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 6659f47b4a..d39d735a46 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -36,7 +36,7 @@ datum/controller/game_controller/New() datum/controller/game_controller/proc/setup() setup_objects() - setupgenetics() + // setupgenetics() Moved to SSatoms SetupXenoarch() transfer_controller = new @@ -59,6 +59,7 @@ datum/controller/game_controller/proc/setup_objects() //Set up spawn points. populate_spawn_points() +/* admin_notice("Initializing Floor Decals", R_DEBUG) var/list/turfs_with_decals = list() for(var/obj/effect/floor_decal/D in world) @@ -111,3 +112,4 @@ datum/controller/game_controller/proc/setup_objects() if(!QDELETED(lift)) lift.initialize() CHECK_SLEEP_MASTER + */ \ No newline at end of file diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm new file mode 100644 index 0000000000..6b5669878c --- /dev/null +++ b/code/controllers/subsystems/atoms.dm @@ -0,0 +1,145 @@ +#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 = INIT_ORDER_ATOMS + flags = SS_NO_FIRE + + var/initialized = INITIALIZATION_INSSATOMS + // var/list/created_atoms // This is never used, so don't bother. ~Leshana + var/old_initialized + + var/list/late_loaders + var/list/created_atoms + + var/list/BadInitializeCalls = list() + +/datum/controller/subsystem/atoms/Initialize(timeofday) + setupgenetics() //to set the mutations' place in structural enzymes, so initializers know where to put mutations. + initialized = INITIALIZATION_INNEW_MAPLOAD + to_world_log("Initializing objects") + admin_notice("Initializing objects", R_DEBUG) + InitializeAtoms() + return ..() + +/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms) + if(initialized == INITIALIZATION_INSSATOMS) + return + + initialized = INITIALIZATION_INNEW_MAPLOAD + + 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) + if(InitAtom(I, mapload_arg)) + atoms -= I + CHECK_TICK + else + count = 0 + for(var/atom/A in world) + if(!A.initialized) + InitAtom(A, mapload_arg) + ++count + CHECK_TICK + + log_world("Initialized [count] atoms") + + initialized = INITIALIZATION_INNEW_REGULAR + + if(late_loaders.len) + for(var/I in late_loaders) + var/atom/A = I + A.LateInitialize() + CHECK_TICK + testing("Late initialized [late_loaders.len] atoms") + late_loaders.Cut() + + // Nothing ever checks return value of this proc, so don't bother. If this ever changes fix code in /atom/New() ~Leshana + // 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 || QDELING(A) + +/datum/controller/subsystem/atoms/proc/map_loader_begin() + old_initialized = initialized + initialized = INITIALIZATION_INSSATOMS + +/datum/controller/subsystem/atoms/proc/map_loader_stop() + initialized = old_initialized + +/datum/controller/subsystem/atoms/Recover() + initialized = SSatoms.initialized + if(initialized == INITIALIZATION_INNEW_MAPLOAD) + InitializeAtoms() + old_initialized = SSatoms.old_initialized + 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" + +/datum/controller/subsystem/atoms/Shutdown() + var/initlog = InitLog() + if(initlog) + //text2file(initlog, "[GLOB.log_directory]/initialize.log") + var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day") + text2file(initlog, "data/logs/[date_string]-initialize.log") + +#undef BAD_INIT_QDEL_BEFORE +#undef BAD_INIT_DIDNT_INIT +#undef BAD_INIT_SLEPT +#undef BAD_INIT_NO_HINT diff --git a/code/controllers/subsystems/floor_decals.dm b/code/controllers/subsystems/floor_decals.dm new file mode 100644 index 0000000000..39e4515d0d --- /dev/null +++ b/code/controllers/subsystems/floor_decals.dm @@ -0,0 +1,28 @@ +// +// Floor Decals Initialization Subsystem +// This is part of the giant decal hack that works around a BYOND bug where DreamDaemon will crash if you +// update overlays on turfs too much. +// The master_controller on Polaris used to init decals prior to initializing areas (which initilized turfs) +// Now that we switched to subsystems we still want to do the same thing, so this takes care of it. +// +SUBSYSTEM_DEF(floor_decals) + name = "Floor Decals" + init_order = INIT_ORDER_DECALS + flags = SS_NO_FIRE + +/datum/controller/subsystem/floor_decals/Initialize(timeofday) + if(floor_decals_initialized) + return ..() + to_world_log("Initializing Floor Decals") + admin_notice("Initializing Floor Decals", R_DEBUG) + var/list/turfs_with_decals = list() + for(var/obj/effect/floor_decal/D in world) + var/T = D.add_to_turf_decals() + if(T) turfs_with_decals |= T + CHECK_TICK + for(var/item in turfs_with_decals) + var/turf/T = item + if(T.decals) T.apply_decals() + CHECK_TICK + floor_decals_initialized = TRUE + return ..() diff --git a/code/controllers/subsystems/machines.dm b/code/controllers/subsystems/machines.dm index 7738544024..f8c353c43d 100644 --- a/code/controllers/subsystems/machines.dm +++ b/code/controllers/subsystems/machines.dm @@ -33,8 +33,9 @@ SUBSYSTEM_DEF(machines) var/list/current_run = list() /datum/controller/subsystem/machines/Initialize(timeofday) - SSmachines.makepowernets() - // TODO - Move world-creation time setup of atmos machinery and pipenets to here + makepowernets() + admin_notice("Initializing atmos machinery.", R_DEBUG) + setup_atmos_machinery(global.machines) fire() ..() @@ -53,13 +54,33 @@ SUBSYSTEM_DEF(machines) for(var/datum/powernet/PN in powernets) qdel(PN) powernets.Cut() + setup_powernets_for_cables(cable_list) - for(var/obj/structure/cable/PC in cable_list) +/datum/controller/subsystem/machines/proc/setup_powernets_for_cables(list/cables) + for(var/obj/structure/cable/PC in cables) if(!PC.powernet) var/datum/powernet/NewPN = new() NewPN.add_cable(PC) propagate_network(PC,PC.powernet) +/datum/controller/subsystem/machines/proc/setup_atmos_machinery(list/atmos_machines) + for(var/obj/machinery/atmospherics/machine in atmos_machines) + machine.atmos_init() + CHECK_TICK + + for(var/obj/machinery/atmospherics/machine in atmos_machines) + machine.build_network() + CHECK_TICK + + for(var/obj/machinery/atmospherics/unary/U in atmos_machines) + if(istype(U, /obj/machinery/atmospherics/unary/vent_pump)) + var/obj/machinery/atmospherics/unary/vent_pump/T = U + T.broadcast_status() + else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber)) + var/obj/machinery/atmospherics/unary/vent_scrubber/T = U + T.broadcast_status() + CHECK_TICK + /datum/controller/subsystem/machines/stat_entry() var/msg = list() msg += "C:{" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 0c5fe0e7de..e70c7325e4 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -25,11 +25,15 @@ ..() -/area/proc/initialize() +/area/initialize() + . = ..() if(!requires_power || !apc) power_light = 0 power_equip = 0 power_environ = 0 + return INITIALIZE_HINT_LATELOAD + +/area/LateInitialize() power_change() // all machines set to current power level, also updates lighting icon /area/proc/get_contents() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index c8a9c1e1b5..b00bf09529 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -24,13 +24,53 @@ //Detective Work, used for the duplicate data points kept in the scanners var/list/original_atom + // Track if we are already had initialize() called to prevent double-initialization. + var/initialized = FALSE -//atom creation method that preloads variables at creation -/atom/New() +/atom/New(loc, ...) // Don't call ..() unless /datum/New() ever exists + + // During dynamic mapload (reader.dm) this assigns the var overrides from the .dmm file + // Native BYOND maploading sets those vars before invoking New(), by doing this FIRST we come as close to that behavior as we can. if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New() _preloader.load(src) + // Pass our arguments to InitAtom so they can be passed to initialize(), but replace 1st with if-we're-during-mapload. + var/do_initialize = SSatoms && SSatoms.initialized // Workaround our non-ideal initialization order: SSatoms may not exist yet. + //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. No sense continuing + return + + // Uncomment if anything ever uses the return value of SSatoms.InitializeAtoms ~Leshana + // If a map is being loaded, it might want to know about newly created objects so they can be handled. + // var/list/created = SSatoms.created_atoms + // if(created) + // created += src + +// Note: I removed "auto_init" feature (letting types disable auto-init) since it shouldn't be needed anymore. +// You can replicate the same by checking the value of the first parameter to initialize() ~Leshana + +// Called after New if the map is being loaded, with mapload = TRUE +// Called from base of New if the map is not being loaded, with mapload = FALSE +// 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 code/__defines/subsystems.dm +/atom/proc/initialize(mapload, ...) + if(QDELETED(src)) + crash_with("GC: -- [type] had initialize() called after qdel() --") + if(initialized) + crash_with("Warning: [src]([type]) initialized multiple times!") + initialized = TRUE + return INITIALIZE_HINT_NORMAL + +// Called after all object's normal initialize() if initialize() returns INITIALIZE_HINT_LATELOAD +/atom/proc/LateInitialize() + return + /atom/proc/reveal_blood() return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 2dba31d578..0cd09b8a57 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -18,15 +18,6 @@ var/icon_scale = 1 // Used to scale icons up or down in update_transform(). var/old_x = 0 var/old_y = 0 - var/auto_init = 1 - -/atom/movable/New() - ..() - if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING) - if(SScreation && SScreation.map_loading) // If a map is being loaded, newly created objects need to wait for it to finish. - SScreation.atoms_needing_initialize += src - else - initialize() /atom/movable/Destroy() . = ..() @@ -47,10 +38,6 @@ pulledby.pulling = null pulledby = null -/atom/movable/proc/initialize() - if(QDELETED(src)) - crash_with("GC: -- [type] had initialize() called after qdel() --") - /atom/movable/Bump(var/atom/A, yes) if(src.throwing) src.throw_impact(A) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 2e881f6583..c616d1ee5b 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -118,10 +118,13 @@ Class Procs: ..(l) if(d) set_dir(d) - START_MACHINE_PROCESSING(src) if(circuit) circuit = new circuit(src) +/obj/machinery/initialize() + . = ..() + START_MACHINE_PROCESSING(src) + /obj/machinery/Destroy() STOP_MACHINE_PROCESSING(src) if(component_parts) diff --git a/code/game/turfs/flooring/turf_overlay_holder.dm b/code/game/turfs/flooring/turf_overlay_holder.dm index a0326b8240..c12f727a0b 100644 --- a/code/game/turfs/flooring/turf_overlay_holder.dm +++ b/code/game/turfs/flooring/turf_overlay_holder.dm @@ -16,7 +16,12 @@ var/global/floor_decals_initialized = FALSE icon = null icon_state = null mouse_opacity = 0 - auto_init = 0 + // auto_init = 0 + +/atom/movable/turf_overlay_holder/initialize() + // doesn't need special init + initialized = TRUE + return INITIALIZE_HINT_NORMAL /atom/movable/turf_overlay_holder/New(var/atom/newloc) ..() diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm index bd85fe8be8..cbf492b081 100644 --- a/code/game/turfs/unsimulated.dm +++ b/code/game/turfs/unsimulated.dm @@ -1,4 +1,5 @@ /turf/unsimulated name = "command" oxygen = MOLES_O2STANDARD - nitrogen = MOLES_N2STANDARD \ No newline at end of file + nitrogen = MOLES_N2STANDARD + initialized = TRUE // Don't call init on unsimulated turfs (at least not yet) diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index 9d612f508d..ea7216dfd3 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -27,7 +27,7 @@ use_power = 1 idle_power_usage = 100 - var/initialized = 0 // Map-placed ones break if seeds are loaded right at the start of the round, so we do it on the first interaction + var/seeds_initialized = 0 // Map-placed ones break if seeds are loaded right at the start of the round, so we do it on the first interaction var/list/datum/seed_pile/piles = list() var/list/starting_seeds = list() var/list/scanner = list() // What properties we can view @@ -135,7 +135,7 @@ if (..()) return - if (!initialized) + if (!seeds_initialized) for(var/typepath in starting_seeds) var/amount = starting_seeds[typepath] if(isnull(amount)) amount = 1 @@ -143,7 +143,7 @@ for (var/i = 1 to amount) var/O = new typepath add(O) - initialized = 1 + seeds_initialized = 1 var/dat = "