[MIRROR] Sourced Component Backend [MDB IGNORE] (#19665)

* Sourced Component Backend (#73571)

## About The Pull Request
Adds a backend for sourced components. which was requested by @ Fikou
Also cleans up a little bit of the AddComponent logic

## Why It's Good For The Game

Backend for fancy stuff and having a component from multiple sources

---------

Signed-off-by: GitHub <noreply@ github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>

* Sourced Component Backend

---------

Signed-off-by: GitHub <noreply@ github.com>
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-03-04 19:55:32 -08:00
committed by GitHub
co-authored by Mothblocks Zephyr
parent c41ff0aaa6
commit 0df0569321
3 changed files with 108 additions and 47 deletions
+97 -47
View File
@@ -38,6 +38,9 @@
*/
var/can_transfer = FALSE
/// A lazy list of the sources for this component
var/list/sources
/**
* Create a new component.
*
@@ -165,6 +168,27 @@
/datum/component/proc/UnregisterFromParent()
return
/**
* Called when the component has a new source registered
*/
/datum/component/proc/on_source_add(source)
SHOULD_CALL_PARENT(TRUE)
if(dupe_mode != COMPONENT_DUPE_SOURCES)
CRASH("Component '[type]' does not use sources but has been given a source")
LAZYOR(sources, source)
/**
* Called when the component has a source removed.
* You probably want to call parent after you do your logic because at the end of this we qdel if we have no sources remaining!
*/
/datum/component/proc/on_source_remove(source)
SHOULD_CALL_PARENT(TRUE)
if(dupe_mode != COMPONENT_DUPE_SOURCES)
CRASH("Component '[type]' does not use sources but is trying to remove a source")
LAZYREMOVE(sources, source)
if(!LAZYLEN(sources))
qdel(src)
/**
* Register to listen for a signal from the passed in target
*
@@ -411,74 +435,100 @@
*
* Properly handles duplicate situations based on the `dupe_mode` var
*/
/datum/proc/_AddComponent(list/raw_args)
var/new_type = raw_args[1]
var/datum/component/nt = new_type
/datum/proc/_AddComponent(list/raw_args, source)
var/original_type = raw_args[1]
var/datum/component/component_type = original_type
if(QDELING(src))
CRASH("Attempted to add a new component of type \[[nt]\] to a qdeleting parent of type \[[type]\]!")
CRASH("Attempted to add a new component of type \[[component_type]\] to a qdeleting parent of type \[[type]\]!")
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/dupe_mode = initial(component_type.dupe_mode)
var/dupe_type = initial(component_type.dupe_type)
var/uses_sources = (dupe_mode == COMPONENT_DUPE_SOURCES)
if(uses_sources && !source)
CRASH("Attempted to add a sourced component of type '[component_type]' to '[type]' without a source!")
else if(!uses_sources && source)
CRASH("Attempted to add a normal component of type '[component_type]' to '[type]' with a source!")
var/datum/component/old_comp
var/datum/component/new_comp
var/datum/component/old_component
var/datum/component/new_component
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
if(ispath(component_type))
if(component_type == /datum/component)
CRASH("[component_type] attempted instantiation!")
else
new_comp = nt
nt = new_comp.type
new_component = component_type
component_type = new_component.type
raw_args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED && dm != COMPONENT_DUPE_SELECTIVE)
if(!dt)
old_comp = GetExactComponent(nt)
if(dupe_mode != COMPONENT_DUPE_ALLOWED && dupe_mode != COMPONENT_DUPE_SELECTIVE)
if(!dupe_type)
old_component = GetExactComponent(component_type)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
old_component = GetComponent(dupe_type)
if(old_component)
switch(dupe_mode)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(!new_component)
new_component = new component_type(raw_args)
if(!QDELETED(new_component))
old_component.InheritComponent(new_component, TRUE)
QDEL_NULL(new_component)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(!new_component)
new_component = new component_type(raw_args)
if(!QDELETED(new_component))
new_component.InheritComponent(old_component, FALSE)
QDEL_NULL(old_component)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
if(!new_component)
var/list/arguments = raw_args.Copy(2)
arguments.Insert(1, null, TRUE)
old_comp.InheritComponent(arglist(arguments))
old_component.InheritComponent(arglist(arguments))
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
else if(dm == COMPONENT_DUPE_SELECTIVE)
old_component.InheritComponent(new_component, TRUE)
if(COMPONENT_DUPE_SOURCES)
if(source in old_component.sources)
return old_component // source already registered, no work to do
old_component.on_source_add(source)
else if(!new_component)
new_component = new component_type(raw_args) // There's a valid dupe mode but there's no old component, act like normal
else if(dupe_mode == COMPONENT_DUPE_SELECTIVE)
var/list/arguments = raw_args.Copy()
arguments[1] = new_comp
arguments[1] = new_component
var/make_new_component = TRUE
for(var/datum/component/existing_component as anything in GetComponents(new_type))
for(var/datum/component/existing_component as anything in GetComponents(original_type))
if(existing_component.CheckDupeComponent(arglist(arguments)))
make_new_component = FALSE
QDEL_NULL(new_comp)
QDEL_NULL(new_component)
break
if(!new_comp && make_new_component)
new_comp = new nt(raw_args)
else if(!new_comp)
new_comp = new nt(raw_args) // Dupes are allowed, act like normal
if(!new_component && make_new_component)
new_component = new component_type(raw_args)
else if(!new_component)
new_component = new component_type(raw_args) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
if(!old_component && !QDELETED(new_component)) // Nothing related to duplicate components happened and the new component is healthy
if(uses_sources) // make sure they have the source added if they use sources
new_component.on_source_add(source)
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_component)
return new_component
return old_component
/**
* Removes a component source from this datum
*/
/datum/proc/RemoveComponentSource(source, datum/component/component_type)
if(ispath(component_type))
component_type = GetExactComponent(component_type)
if(!component_type)
CRASH("Attempted to remove a null or non-existent component '[component_type]' from '[type]'")
component_type.on_source_remove(source)
/**
* Get existing component of type, or create it and return a reference to it