Files
Bubberstation/code/datums/elements/_element.dm
Mothblocks 60ee087b16 Remove ELEMENT_DETACH on everything that doesn't need it, rename to ELEMENT_DETACH_ON_HOST_DESTROY + a PSA (about 0.2s init time savings) (#70972)
ELEMENT_DETACH is **not** a requirement to having `Detach` called.
Detach is always called when the element itself is destroyed.

ELEMENT_DETACH is a flag that when set, makes sure Detach is called when
the atom destroys.

Sometimes you want this, for instance:

```dm
/datum/element/point_of_interest/Detach(datum/target)
	SSpoints_of_interest.on_poi_element_removed(target)
	return ..()
```

This Detach cleans up a reference that would have hung if target was
destroyed without this being called.

However, most uses of Detach are cleaning up signals. Signals are
automatically cleaned up when something is destroyed. You do not need
ELEMENT_DETACH in this case, and it slows down init. This also includes
somewhat more complex stuff, like removing overlays on the source
object. It's getting deleted anyway, you don't care!

I have removed all uses of ELEMENT_DETACH that seemed superfluous. I
have also renamed it to `ELEMENT_DETACH_ON_HOST_DESTROY` to make its
purpose more clear, as me and a lot of other maintainers misunderstood
what it did,

---

An update to this, ELEMENT_DETACH *is* needed for anything that can
register to a turf, as turfs do not clear their signals on destroy.
2022-11-05 15:00:59 +01:00

68 lines
2.2 KiB
Plaintext

/**
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
/datum/element
/// Option flags for element behaviour
var/element_flags = NONE
/**
* The index of the first attach argument to consider for duplicate elements
*
* Is only used when flags contains [ELEMENT_BESPOKE]
*
* This is infinity so you must explicitly set this
*/
var/id_arg_index = INFINITY
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
SHOULD_CALL_PARENT(TRUE)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
if(element_flags & ELEMENT_DETACH_ON_HOST_DESTROY)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/OnTargetDelete, override = TRUE)
/datum/element/proc/OnTargetDelete(datum/source, force)
SIGNAL_HANDLER
Detach(source)
/// Deactivates the functionality defines by the element on the given datum
/datum/element/proc/Detach(datum/source, ...)
SIGNAL_HANDLER
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
if(!force)
return QDEL_HINT_LETMELIVE
SSdcs.elements_by_type -= type
return ..()
//DATUM PROCS
/// Finds the singleton for the element type given and attaches it to src
/datum/proc/_AddElement(list/arguments)
if(QDELING(src))
CRASH("We just tried to add an element to a qdeleted datum, something is fucked")
var/datum/element/ele = SSdcs.GetElement(arguments)
arguments[1] = src
if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
/**
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
*/
/datum/proc/_RemoveElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
if(ele.element_flags & ELEMENT_COMPLEX_DETACH)
arguments[1] = src
ele.Detach(arglist(arguments))
else
ele.Detach(src)