mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
200 lines
6.2 KiB
Plaintext
200 lines
6.2 KiB
Plaintext
SUBSYSTEM_DEF(atoms)
|
|
name = "Atoms"
|
|
init_order = INIT_ORDER_ATOMS
|
|
flags = SS_NO_FIRE
|
|
|
|
/// A stack of list(source, desired initialized state)
|
|
/// We read the source of init changes from the last entry, and assert that all changes will come with a reset
|
|
var/list/initialized_state = list()
|
|
var/base_initialized
|
|
|
|
var/initialized = INITIALIZATION_INSSATOMS
|
|
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()
|
|
init_start_time = world.time
|
|
|
|
initialized = INITIALIZATION_INNEW_MAPLOAD
|
|
InitializeAtoms()
|
|
initialized = INITIALIZATION_INNEW_REGULAR
|
|
|
|
return SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms, list/atoms_to_return)
|
|
if(initialized == INITIALIZATION_INSSATOMS)
|
|
return
|
|
|
|
// Generate a unique mapload source for this run of InitializeAtoms
|
|
var/static/uid = 0
|
|
uid = (uid + 1) % (SHORT_REAL_LIMIT - 1)
|
|
var/source = "subsystem init [uid]"
|
|
set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, source)
|
|
|
|
// 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, source)
|
|
clear_tracked_initalize(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()
|
|
testing("Late initialized [late_loaders.len] atoms")
|
|
late_loaders.Cut()
|
|
|
|
if (created_atoms)
|
|
atoms_to_return += created_atoms
|
|
created_atoms = null
|
|
|
|
for (var/queued_deletion in queued_deletions)
|
|
qdel(queued_deletion)
|
|
|
|
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 solely so a runtime in the creation logic doesn't cause initialized to totally break
|
|
/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null, mapload_source = null)
|
|
if (atoms_to_return)
|
|
LAZYINITLIST(created_atoms)
|
|
|
|
#ifdef TESTING
|
|
var/count
|
|
#endif
|
|
|
|
var/list/mapload_arg = list(TRUE)
|
|
|
|
if(atoms)
|
|
#ifdef TESTING
|
|
count = atoms.len
|
|
#endif
|
|
|
|
for(var/I in 1 to atoms.len)
|
|
var/atom/A = atoms[I]
|
|
if(!(A.flags & ATOM_INITIALIZED))
|
|
// Unrolled CHECK_TICK setup to let us enable/disable mapload based off source
|
|
if(TICK_CHECK)
|
|
clear_tracked_initalize(mapload_source)
|
|
stoplag()
|
|
if(mapload_source)
|
|
set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source)
|
|
PROFILE_INIT_ATOM_BEGIN()
|
|
InitAtom(A, TRUE, mapload_arg)
|
|
PROFILE_INIT_ATOM_END(A)
|
|
else
|
|
#ifdef TESTING
|
|
count = 0
|
|
#endif
|
|
|
|
for(var/atom/A as anything in world)
|
|
if(!(A.flags & ATOM_INITIALIZED))
|
|
PROFILE_INIT_ATOM_BEGIN()
|
|
InitAtom(A, FALSE, mapload_arg)
|
|
PROFILE_INIT_ATOM_END(A)
|
|
#ifdef TESTING
|
|
++count
|
|
#endif
|
|
if(TICK_CHECK)
|
|
clear_tracked_initalize(mapload_source)
|
|
stoplag()
|
|
if(mapload_source)
|
|
set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source)
|
|
|
|
#ifdef TESTING
|
|
testing("Initialized [count] atoms")
|
|
#endif
|
|
|
|
/datum/controller/subsystem/atoms/proc/map_loader_begin(source)
|
|
set_tracked_initalized(INITIALIZATION_INSSATOMS, source)
|
|
|
|
/datum/controller/subsystem/atoms/proc/map_loader_stop(source)
|
|
clear_tracked_initalize(source)
|
|
|
|
/// Returns the source currently modifying SSatom's init behavior
|
|
/datum/controller/subsystem/atoms/proc/get_initialized_source()
|
|
var/state_length = length(initialized_state)
|
|
if(!state_length)
|
|
return null
|
|
return initialized_state[state_length][1]
|
|
|
|
/// Use this to set initialized to prevent error states where the old initialized is overridden, and we end up losing all context
|
|
/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentally
|
|
/datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source)
|
|
if(!length(initialized_state))
|
|
base_initialized = initialized
|
|
initialized_state += list(list(source, state))
|
|
initialized = state
|
|
|
|
/datum/controller/subsystem/atoms/proc/clear_tracked_initalize(source)
|
|
if(!length(initialized_state))
|
|
return
|
|
for(var/i in length(initialized_state) to 1 step -1)
|
|
if(initialized_state[i][1] == source)
|
|
initialized_state.Cut(i, i+1)
|
|
break
|
|
|
|
if(!length(initialized_state))
|
|
initialized = base_initialized
|
|
base_initialized = INITIALIZATION_INNEW_REGULAR
|
|
return
|
|
initialized = initialized_state[length(initialized_state)][2]
|
|
|
|
/// Returns TRUE if anything is currently being initialized
|
|
/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(mapload)\n"
|
|
if(fails & BAD_INIT_NO_HINT)
|
|
. += "- Didn't return an Initialize hint\n"
|
|
if(fails & BAD_INIT_QDEL_BEFORE)
|
|
. += "- Qdel'd before Initialize proc ran\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)
|
|
text2file(initlog, "[GLOB.log_directory]-initialize.log")
|