mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-20 21:16:39 +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 <!-- 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. -->
246 lines
7.5 KiB
Plaintext
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
|