Files
Aurora.3/code/game/atom/atoms_initializing_EXPENSIVE.dm
Fluffy 41a05bc196 Refactored the abstract meta propriety (#19797)
Refactored the abstract meta propriety into defines.
It's now more easy to spot/see abstract types thanks to the macro that
defines them.
Added a check on initialization of atoms to avoid spawning abstract
types.
Made the spawn_atom proc check for abstractness.
Made the spawn_atom proc use tgui_list for types list shorter than 1000
elements, which enables to search in them. It's too laggy on larger
lists so above 1000 it uses the builtin input.
Made the spawn_atom use a list subtraction instead of a double list,
it's lighter on memory and processing.
2024-08-23 10:49:28 +00:00

172 lines
6.4 KiB
Plaintext

/// 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.gc_destroyed > init_start_time)
BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE
return TRUE
// This is handled and battle tested by dreamchecker. Limit to UNIT_TEST 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(GLOB.use_preloader && (src.type == GLOB._preloader_path))//in case the instanciated atom is creating other atoms in New()
GLOB._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)
//Finally an aurora snowflake code that matters,
//this try to ensure noone is stupid enough to instantiate an abstract type
if(is_abstract(src))
var/datum/space_level/L = SSmapping.get_level(z)
stack_trace("Atom [src] ([type]) \[ X:[x] Y:[y] Z:[z] (Space level: [L ? L.name : "NOT FOUND"]) \] is abstract, but is trying to initialize!")
return INITIALIZE_HINT_QDEL
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)