mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-20 13:16:34 +01:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request title <!-- Describe The Pull Request. Please be sure every change is documented or this can delay review and even discourage maintainers from merging your PR! --> ## Why It's Good For The Game <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 add: new adminbuse view matrix editor code: cleanup legacy stuff & moved them into their own respective dropdown option code: use tg display-mutable-appearance /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->
125 lines
4.6 KiB
Plaintext
125 lines
4.6 KiB
Plaintext
/// Creates a weakref to the given input.
|
|
/// * See /datum/weakref's documentation for more information.
|
|
/proc/WEAKREF(datum/input)
|
|
if(istype(input) && !QDELETED(input))
|
|
if(isweakref(input))
|
|
return input
|
|
|
|
if(!input.weak_reference)
|
|
input.weak_reference = new /datum/weakref(input)
|
|
return input.weak_reference
|
|
|
|
/// Creates a weakref to the given input.
|
|
/// * See /datum/weakref's documentation for more information.
|
|
/// * Ignores if the input is qdeleted.
|
|
/proc/WEAKREF_UNSAFE(datum/input)
|
|
if(istype(input))
|
|
if(isweakref(input))
|
|
return input
|
|
|
|
if(!input.weak_reference)
|
|
input.weak_reference = new /datum/weakref(input)
|
|
return input.weak_reference
|
|
|
|
/datum/proc/create_weakref() //Forced creation for admin proccalls
|
|
return WEAKREF(src)
|
|
|
|
/**
|
|
* A weakref holds a non-owning reference to a datum.
|
|
* The datum can be referenced again using `resolve()`.
|
|
*
|
|
* To figure out why this is important, you must understand how deletion in
|
|
* BYOND works.
|
|
*
|
|
* Imagine a datum as a TV in a living room. When one person enters to watch
|
|
* TV, they turn it on. Others can come into the room and watch the TV.
|
|
* When the last person leaves the room, they turn off the TV because it's
|
|
* no longer being used.
|
|
*
|
|
* A datum being deleted tells everyone who's watching the TV to stop.
|
|
* If everyone leaves properly (AKA cleaning up their references), then the
|
|
* last person will turn off the TV, and everything is well.
|
|
* However, if someone is resistant (holds a hard reference after deletion),
|
|
* then someone has to walk in, drag them away, and turn off the TV forecefully.
|
|
* This process is very slow, and it's known as hard deletion.
|
|
*
|
|
* This is where weak references come in. Weak references don't count as someone
|
|
* watching the TV. Thus, when what it's referencing is destroyed, it will
|
|
* hopefully clean up properly, and limit hard deletions.
|
|
*
|
|
* A common use case for weak references is holding onto what created itself.
|
|
* For example, if a machine wanted to know what its last user was, it might
|
|
* create a `var/mob/living/last_user`. However, this is a strong reference to
|
|
* the mob, and thus will force a hard deletion when that mob is deleted.
|
|
* It is often better in this case to instead create a weakref to the user,
|
|
* meaning this type definition becomes `var/datum/weakref/last_user`.
|
|
*
|
|
* A good rule of thumb is that you should hold strong references to things
|
|
* that you *own*. For example, a dog holding a chew toy would be the owner
|
|
* of that chew toy, and thus a `var/obj/item/chew_toy` reference is fine
|
|
* (as long as it is cleaned up properly).
|
|
* However, a chew toy does not own its dog, so a `var/mob/living/dog/owner`
|
|
* might be inferior to a weakref.
|
|
* This is also a good rule of thumb to avoid circular references, such as the
|
|
* chew toy example. A circular reference that doesn't clean itself up properly
|
|
* will always hard delete.
|
|
*/
|
|
/datum/weakref
|
|
var/reference
|
|
|
|
/datum/weakref/New(datum/thing)
|
|
reference = REF(thing)
|
|
|
|
/datum/weakref/Destroy(force)
|
|
var/datum/target = resolve()
|
|
qdel(target)
|
|
|
|
if(!force)
|
|
return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore.
|
|
target?.weak_reference = null
|
|
return ..()
|
|
|
|
/**
|
|
* Retrieves the datum that this weakref is referencing.
|
|
*
|
|
* This will return `null` if the datum was deleted. This MUST be respected.
|
|
*/
|
|
/datum/weakref/proc/resolve()
|
|
var/datum/D = locate(reference)
|
|
return (!QDELETED(D) && D.weak_reference == src) ? D : null
|
|
|
|
/**
|
|
* SERIOUSLY READ THE AUTODOC COMMENT FOR THIS PROC BEFORE EVEN THINKING ABOUT USING IT
|
|
*
|
|
* Like resolve, but doesn't care if the datum is being qdeleted but hasn't been deleted yet.
|
|
*
|
|
* The return value of this proc leaves hanging references if the datum is being qdeleted but hasn't been deleted yet.
|
|
*
|
|
* Do not do anything that would create a lasting reference to the return value, such as giving it a tag, putting it on the map,
|
|
* adding it to an atom's contents or vis_contents, giving it a key (if it's a mob), attaching it to an atom (if it's an image),
|
|
* or assigning it to a datum or list referenced somewhere other than a temporary value.
|
|
*
|
|
* Unless you're resolving a weakref to a datum in a COMSIG_QDELETING signal handler registered on that very same datum,
|
|
* just use resolve instead.
|
|
*/
|
|
/datum/weakref/proc/hard_resolve()
|
|
var/datum/D = locate(reference)
|
|
return (D?.weak_reference == src) ? D : null
|
|
|
|
/datum/weakref/vv_get_dropdown()
|
|
. = ..()
|
|
VV_DROPDOWN_OPTION(VV_HK_WEAKREF_RESOLVE, "Go to reference")
|
|
|
|
/datum/weakref/vv_do_topic(list/href_list)
|
|
. = ..()
|
|
|
|
if(!.)
|
|
return
|
|
|
|
if(href_list[VV_HK_WEAKREF_RESOLVE])
|
|
if(!check_rights(NONE))
|
|
return
|
|
var/datum/R = resolve()
|
|
if(R)
|
|
usr.client.debug_variables(R)
|