diff --git a/code/datums/components/README.md b/code/datums/components/README.md index b76736debb8..15001bbfd7c 100644 --- a/code/datums/components/README.md +++ b/code/datums/components/README.md @@ -30,14 +30,18 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * Lazy associated list of type -> component/list of components. 1. `/datum/component/var/enabled` (protected, boolean) * If the component is enabled. If not, it will not react to signals - * TRUE by default + * `TRUE` by default 1. `/datum/component/var/dupe_mode` (protected, enum) - * How multiple components of the exact same type are handled when added to the datum. + * How duplicate component types are handled when added to the datum. * `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it * `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added * `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it +1. `/datum/component/var/dupe_type` (protected, type) + * Definition of a duplicate component type + * `null` means exact match on `type` + * Any other type means that and all subtypes 1. `/datum/component/var/list/signal_procs` (private) - * Associated lazy list of signals -> callbacks that will be run when the parent datum recieves that signal + * Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum recieves that signal 1. `/datum/component/var/datum/parent` (protected, read-only) * The datum this component belongs to @@ -56,6 +60,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * Sends the `COMSIG_COMPONENT_ADDED` signal to the datum * All components a datum owns are deleted with the datum * Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set +1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final) + * Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead 1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract) * Called on a component's `parent` after a signal recieved causes it to activate. `src` is the parameter * Will only be called if a component's callback returns `TRUE` @@ -66,18 +72,24 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo 1. `/datum/proc/SendSignal(signal, ...)` (public, final) * Call to send a signal to the components of the target datum * Extra arguments are to be specified in the signal definition -1. `/datum/component/New(datum/parent, ...)` (protected, virtual) - * Forwarded the arguments from `AddComponent()` -1. `/datum/component/Destroy()` (virtual) +1. `/datum/component/New(datum/parent, ...)` (private, final) + * Runs internal setup for the component + * Extra arguments are passed to `Initialize()` +1. `/datum/component/Initialize(...)` (abstract, no-sleep) + * Called by `New()` with the same argments excluding `parent` + * Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used + * Signals will not be recieved while this function is running + * Component may be deleted after this function completes without being attached +1. `/datum/component/Destroy()` (virtual, no-sleep) * Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted * Properly removes the component from `parent` and cleans up references -1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract) +1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract, no-sleep) * Called on a component when a component of the same type was added to the same parent * See `/datum/component/var/dupe_mode` * `C`'s type will always be the same of the called component 1. `/datum/component/proc/AfterComponentActivated()` (abstract) * Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called -1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract) +1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep) * Called before the new `parent` is assigned in `TakeComponent()`, after the remove signal, before the added signal * Allows the component to react to ownership transfers 1. `/datum/component/proc/_RemoveNoSignal()` (private, final) @@ -93,9 +105,4 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo * Called when a component recieves any signal and is enabled * Default implementation looks if the signal is registered and runs the appropriate proc -### See signals and their arguments in __DEFINES\components.dm - -## Examples - Material Containers: #29268 (Too many GetComponent calls, but not bad) - Slips: #00000 (PR DIS) - Powercells: (TODO) \ No newline at end of file +### See/Define signals and their arguments in __DEFINES\components.dm diff --git a/code/datums/components/component.dm b/code/datums/components/component.dm index 9ff9cc592f9..92ac9a4767c 100644 --- a/code/datums/components/component.dm +++ b/code/datums/components/component.dm @@ -1,22 +1,35 @@ /datum/component var/enabled = TRUE var/dupe_mode = COMPONENT_DUPE_HIGHLANDER + var/dupe_type var/list/signal_procs var/datum/parent /datum/component/New(datum/P, ...) + parent = P + var/list/arguments = args.Copy() + arguments.Cut(1, 2) + Initialize(arglist(arguments)) + var/dm = dupe_mode if(dm != COMPONENT_DUPE_ALLOWED) - var/datum/component/old = P.GetExactComponent(type) - if(old) - switch(dm) - if(COMPONENT_DUPE_HIGHLANDER) - InheritComponent(old, FALSE) - qdel(old) - if(COMPONENT_DUPE_UNIQUE) - old.InheritComponent(src, TRUE) - qdel(src) - return + var/dt = dupe_type + var/datum/component/old + if(!dt) + old = P.GetExactComponent(type) + else + old = P.GetComponent(dt) + switch(dm) + if(COMPONENT_DUPE_UNIQUE) + old.InheritComponent(src, TRUE) + parent = null //prevent COMPONENT_REMOVING signal + qdel(src) + return + if(COMPONENT_DUPE_HIGHLANDER) + InheritComponent(old, FALSE) + qdel(old) + + //let the others know P.SendSignal(COMSIG_COMPONENT_ADDED, src) //lazy init the parent's dc list @@ -50,7 +63,8 @@ else //only component of this type, no list dc[I] = src - parent = P +/datum/component/proc/Initialize(...) + return /datum/component/Destroy() enabled = FALSE @@ -177,6 +191,11 @@ var/datum/component/C = new nt(arglist(args)) return QDELING(C) ? GetComponent(new_type) : C +/datum/proc/LoadComponent(component_type, ...) + . = GetComponent(component_type) + if(!.) + return AddComponent(arglist(args)) + /datum/proc/TakeComponent(datum/component/C) if(!C) return diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index d445febeb5e..321d407e921 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -3,11 +3,10 @@ var/lube_flags var/mob/slip_victim -/datum/component/slippery/New(datum/P, _intensity, _lube_flags = NONE) - ..() +/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE) intensity = max(_intensity, 0) lube_flags = _lube_flags - if(ismovableatom(P)) + if(ismovableatom(parent)) RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/Slip) else RegisterSignal(COMSIG_ATOM_ENTERED, .proc/Slip)