Files
Letter NandGitHub 31751a9729 update filters (#7456)
<!-- 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

<!-- 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. -->

🆑
code: update filters
/🆑

<!-- 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. -->
2026-01-08 01:35:37 -05:00

246 lines
7.5 KiB
Plaintext

/**
* The absolute base class for everything
*
* A datum instantiated has no physical world prescence, use an atom if you want something
* that actually lives in the world
*
* Be very mindful about adding variables to this class, they are inherited by every single
* thing in the entire game, and so you can easily cause memory usage to rise a lot with careless
* use of variables at this level
*/
/datum
/// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
var/list/status_traits
/// Datum level flags
var/datum_flags = NONE
/// A weak reference to another datum
var/datum/weakref/weak_reference
//* Datum Component System *//
/**
* Components attached to this datum
* Lazy assoclist of type -> component reference or list of component references
*/
var/list/datum_components
/**
* Any datum registered to receive signals from this datum is in this list
*
* Lazy associated list in the structure of `signal:registree/list of registrees`
*/
var/list/comp_lookup
/// Lazy associated list in the structure of `signals:proctype` that are run when the datum receives that signal
var/list/list/datum/callback/signal_procs
/// Is this datum capable of sending signals?
var/signal_enabled = FALSE
//* Cooldown System *//
/*
* Lazy associative list of currently active cooldowns.
*
* cooldowns [ COOLDOWN_INDEX ] = add_timer()
* add_timer() returns the truthy value of -1 when not stoppable, and else a truthy numeric index
*/
var/list/cooldowns
//* Subsystem - Garbage *//
/**
* Tick count time when this object was destroyed.
*
* If this is non zero then the object has been garbage collected and is awaiting either
* a hard del by the GC subsystme, or to be autocollected (if it has no references)
*/
var/gc_destroyed
//* Subsystem - Timer *//
/// Active timers with this datum as the target
var/list/active_timers
//* Subsystem - TGUI *//
/// Open uis owned by this datum
/// Lazy, since this case is semi rare
var/list/datum/tgui/open_uis
//* misc - filters *//
/// List for handling persistent filters.
var/list/filter_data
/// An accursed beast of a list that contains our filters. Why? Because var/list/filters on atoms/images isn't actually a list
/// but a snowflaked skinwalker pretending to be one, which doesn't support half the list procs/operations and the other half behaves weirdly
/// so we cut down on filter creation and appearance update costs by editing *this* list, and then assigning ours to it
var/list/filter_cache
//* misc - reftracking *//
#ifdef REFERENCE_TRACKING
/// When was this datum last touched by a reftracker?
/// If this value doesn't match with the start of the search
/// We know this datum has never been seen before, and we should check it
var/last_find_references = 0
/// How many references we're trying to find when searching
var/references_to_clear = 0
#ifdef REFERENCE_TRACKING_DEBUG
///Stores info about where refs are found, used for sanity checks and testing
var/list/found_refs
#endif
#endif
/**
* Default implementation of clean-up code.
*
* This should be overridden to remove all references pointing to the object being destroyed, if
* you do override it, make sure to call the parent and return it's return value by default
*
* Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion;
* in most cases this is [QDEL_HINT_QUEUE].
*
* The base case is responsible for doing the following
* * Erasing timers pointing to this datum
* * Erasing compenents on this datum
* * Notifying datums listening to signals from this datum that we are going away
*
* Returns [QDEL_HINT_QUEUE]
*/
/datum/proc/Destroy(force=FALSE)
SHOULD_CALL_PARENT(TRUE)
//SHOULD_NOT_SLEEP(TRUE)
tag = null
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
// -- CITADEL REMOVAL --
// This shouldn't be needed; weakref already has resolve() vs hard_resolve().
// We use weakref for GC tracing.
// weak_reference = null //ensure prompt GCing of weakref.
if(active_timers)
var/list/timers = active_timers
active_timers = null
for(var/datum/timedevent/timer as anything in timers)
if (timer.spent && !(timer.timer_flags & TIMER_DELETE_ME))
continue
qdel(timer)
#ifdef REFERENCE_TRACKING
#ifdef REFERENCE_TRACKING_DEBUG
found_refs = null
#endif
#endif
//BEGIN: ECS SHIT
var/list/dc = datum_components
if(dc)
for(var/component_key in dc)
var/component_or_list = dc[component_key]
if(islist(component_or_list))
for(var/datum/component/component as anything in component_or_list)
qdel(component, FALSE)
else
var/datum/component/C = component_or_list
qdel(C, FALSE)
dc.Cut()
clear_signal_refs()
//END: ECS SHIT
return QDEL_HINT_QUEUE
/datum/proc/gc_trace_data()
. = list()
if(length(active_timers))
.["datum-active-timers"] = json_encode(active_timers)
if(length(open_uis))
.["datum-open-uis"] = json_encode(open_uis)
if(length(status_traits))
.["datum-status-traits"] = json_encode(status_traits)
if(length(datum_components))
.["datum-components"] = json_encode(datum_components)
if(length(comp_lookup))
.["datum-component-lookups"] = json_encode(comp_lookup)
///images are pretty generic, this should help a bit with tracking harddels related to them
/image/gc_trace_data()
. = list(
"type" = "[type]",
"refcount" = refcount(src),
"icon" = "[icon]",
"icon_state" = "[icon_state]",
"loc" = loc ? "loc: [loc] ([COORD(loc)])" : "",
)
///Only override this if you know what you're doing. You do not know what you're doing
///This is a threat
/datum/proc/clear_signal_refs()
var/list/lookup = comp_lookup
if(lookup)
for(var/sig in lookup)
var/list/comps = lookup[sig]
if(length(comps))
for(var/datum/component/comp as anything in comps)
comp.UnregisterSignal(src, sig)
else
var/datum/component/comp = comps
comp.UnregisterSignal(src, sig)
comp_lookup = lookup = null
for(var/target in signal_procs)
UnregisterSignal(target, signal_procs[target])
//* Cooldowns *//
/**
* Callback called by a timer to end an associative-list-indexed cooldown.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end.
*/
/proc/end_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
TIMER_COOLDOWN_END(source, index)
/**
* Proc used by stoppable timers to end a cooldown before the time has ran out.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end, passing the time left as an argument.
*/
/proc/reset_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
TIMER_COOLDOWN_END(source, index)
//* Duplication *//
/**
* makes a clone of this datum
*/
/datum/proc/clone()
return new type
//* Serialization *//
/**
* serializes us to a list
* note that *everything* will be trampled down to a number or text.
* do not store raw types.
*
* do not serialize type with this; type should always be stored externally from data.
*/
/datum/proc/serialize()
return list()
/**
* deserializes from a list
*
* @params
* * data - json_decode()'d list.
*
* @return TRUE / FALSE success / failure
*/
/datum/proc/deserialize(list/data)
return TRUE