Implement SSatoms

* Moves proc/initialize() from being on /atom/movable, /are and /turf/simulated to being on /atom - Now turfs can initialize too
* Added the SSatoms subsystem which controls initialization of atoms at roundstart and during normal conditions.
* Disabled the old auto_init = 0 behavior, ALL atoms should get initialized() called on them now.
* Refactored the way initialize() is called during /New() to utilize SSatoms instead of SScreation
* Removed SScreation, as it was only a stop-gap until SSatoms could be ported.
* Updated the maploader to inform SSatoms when it is loading maps instead of SScreation.
* Updated the template map loader to use SSatoms to perform initTemplateBounds
* Renamed 'initialized' var in seed_storage to deconflict.
* Removed usage of auto_init = 0, replaced with a no-op initialize() proc for atoms that don't need initialization.
This commit is contained in:
Leshana
2018-01-26 20:35:13 -05:00
parent f116625c7b
commit 44dc4b7286
18 changed files with 309 additions and 78 deletions

View File

@@ -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

View File

@@ -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("<span class='danger'>Initializing Floor Decals</span>", 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
*/

View File

@@ -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("<span class='danger'>Initializing objects</span>", 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

View File

@@ -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("<span class='danger'>Initializing Floor Decals</span>", 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 ..()

View File

@@ -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("<span class='danger'>Initializing atmos machinery.</span>", 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:{"

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
..()

View File

@@ -2,3 +2,4 @@
name = "command"
oxygen = MOLES_O2STANDARD
nitrogen = MOLES_N2STANDARD
initialized = TRUE // Don't call init on unsimulated turfs (at least not yet)

View File

@@ -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 = "<center><h1>Seed storage contents</h1></center>"
if (piles.len == 0)

View File

@@ -10,7 +10,7 @@
//invisibility = INVISIBILITY_LIGHTING
color = LIGHTING_BASE_MATRIX
icon_state = "light1"
auto_init = 0 // doesn't need special init
//auto_init = 0 // doesn't need special init
blend_mode = BLEND_OVERLAY
var/lum_r = 0
@@ -19,6 +19,11 @@
var/needs_update = FALSE
/atom/movable/lighting_overlay/initialize()
// doesn't need special init
initialized = TRUE
return INITIALIZE_HINT_NORMAL
/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE)
. = ..()
verbs.Cut()

View File

@@ -44,62 +44,40 @@ var/list/global/map_templates = list()
return bounds
/datum/map_template/proc/initTemplateBounds(var/list/bounds)
var/list/obj/machinery/atmospherics/atmos_machines = list()
if (SSatoms.initialized == INITIALIZATION_INSSATOMS)
return // let proper initialisation handle it later
var/list/atom/atoms = list()
var/list/area/areas = list()
// var/list/turf/turfs = list()
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/list/obj/structure/cable/cables = list()
var/list/obj/machinery/atmospherics/atmos_machines = list()
var/list/turf/turfs = block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ]))
for(var/L in turfs)
var/turf/B = L
atoms += B
areas |= B.loc
for(var/A in B)
atoms += A
// turfs += B
areas |= get_area(B)
if(istype(A, /obj/machinery/atmospherics))
if(istype(A, /obj/structure/cable))
cables += A
else if(istype(A, /obj/machinery/atmospherics))
atmos_machines += A
atoms |= areas
var/i = 0
// Apparently when areas get initialize()'d they initialize their turfs as well.
// If this is ever changed, uncomment the block of code below.
// admin_notice("<span class='danger'>Initializing newly created simulated turfs in submap.</span>", R_DEBUG)
// for(var/turf/simulated/T in turfs)
// T.initialize()
// i++
// admin_notice("<span class='danger'>[i] turf\s initialized.</span>", R_DEBUG)
// i = 0
SScreation.initialize_late_atoms()
admin_notice("<span class='danger'>Initializing newly created area(s) in submap.</span>", R_DEBUG)
for(var/area/A in areas)
A.initialize()
i++
admin_notice("<span class='danger'>[i] area\s initialized.</span>", R_DEBUG)
i = 0
admin_notice("<span class='danger'>Initializing newly created atom(s) in submap.</span>", R_DEBUG)
SSatoms.InitializeAtoms(atoms)
admin_notice("<span class='danger'>Initializing atmos pipenets and machinery in submap.</span>", R_DEBUG)
for(var/obj/machinery/atmospherics/machine in atmos_machines)
machine.atmos_init()
i++
for(var/obj/machinery/atmospherics/machine in atmos_machines)
machine.build_network()
for(var/obj/machinery/atmospherics/unary/U in machines)
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
var/obj/machinery/atmospherics/unary/vent_pump/T = U
T.broadcast_status()
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
T.broadcast_status()
admin_notice("<span class='danger'>[i] pipe\s initialized.</span>", R_DEBUG)
SSmachines.setup_atmos_machinery(atmos_machines)
admin_notice("<span class='danger'>Rebuilding powernets due to submap creation.</span>", R_DEBUG)
SSmachines.makepowernets()
SSmachines.setup_powernets_for_cables(cables)
// Ensure all machines in loaded areas get notified of power status
for(var/I in areas)
var/area/A = I
A.power_change()
admin_notice("<span class='danger'>Submap initializations finished.</span>", R_DEBUG)

View File

@@ -304,7 +304,7 @@ var/global/use_preloader = FALSE
first_turf_index++
//turn off base new Initialization until the whole thing is loaded
SScreation.StartLoadingMap()
SSatoms.map_loader_begin()
//instanciate the first /turf
var/turf/T
if(members[first_turf_index] != /turf/template_noop)
@@ -323,7 +323,7 @@ var/global/use_preloader = FALSE
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],crds,no_changeturf)
//Restore initialization to the previous value
SScreation.StopLoadingMap()
SSatoms.map_loader_stop()
////////////////
//Helpers procs
@@ -344,9 +344,9 @@ var/global/use_preloader = FALSE
//custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize
if(TICK_CHECK)
SScreation.StopLoadingMap()
SSatoms.map_loader_stop()
stoplag()
SScreation.StartLoadingMap()
SSatoms.map_loader_begin()
/dmm_suite/proc/create_atom(path, crds)
set waitfor = FALSE

View File

@@ -10,7 +10,7 @@
unacidable = 1
density = 0
opacity = 0 // Don't trigger lighting recalcs gah! TODO - consider multi-z lighting.
auto_init = FALSE // We do not need to be initialize()d
//auto_init = FALSE // We do not need to be initialize()d
var/mob/owner = null // What we are a shadow of.
/mob/zshadow/can_fall()

View File

@@ -40,6 +40,7 @@ var/global/datum/global_init/init = new ()
#define RECOMMENDED_VERSION 501
/world/New()
world.log << "Map Loading Complete"
//logs
var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day")
href_logfile = file("data/logs/[date_string] hrefs.htm")

View File

@@ -174,7 +174,8 @@
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
#include "code\controllers\subsystems\air.dm"
#include "code\controllers\subsystems\airflow.dm"
#include "code\controllers\subsystems\creation.dm"
#include "code\controllers\subsystems\atoms.dm"
#include "code\controllers\subsystems\floor_decals.dm"
#include "code\controllers\subsystems\garbage.dm"
#include "code\controllers\subsystems\lighting.dm"
#include "code\controllers\subsystems\machines.dm"