mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-23 07:05:13 +01:00
9b6e752f3e
## About The Pull Request Continuation of https://github.com/tgstation/tgstation/pull/78857 FOR TOOO LONG WE HAVE SUFF- Ok yeah so like, we made them overlays to save on maptick, but with threaded maptick that is potentially not an issue anymore. I'm opening this pr so I can tm it and see. If it works, it'll save about 50% of lighting object update costs, which is pretty damn good. I'm also removing the fullbright light icon state, since it is barely ever used (it was added as a clientside op, but we don't hit fullbright very much at all so it does nothing but eat my cpu time) Also also changing how SSlighting does its resolution. Rather then waiting for all sources to process, then working on corners and objects, instead we will do all the sources we had at the start, then all the sources after, and so on. The goal is to avoid churn causing the system to constantly choke. it is better to potentially double operate then it is for things to feel horrifically slow. ## Why It's Good For The Game Faster. Also you won't be able to see lights through walls anymore, so mesons will be less dumb. Can maybe bump their nightvision a bit idk we'll see. ## Current Issues to be found ## Changelog 🆑 Absolucy, LemonInTheDark fix: You can no longer see lights through walls when using mesons or when ventcrawling. /🆑 --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
280 lines
9.7 KiB
Plaintext
280 lines
9.7 KiB
Plaintext
#ifdef REFERENCE_TRACKING
|
|
#define REFSEARCH_RECURSE_LIMIT 64
|
|
|
|
#ifdef FAST_REFERENCE_TRACKING
|
|
// typecache of types that almost certainly have no refs, and thus can be safely skipped when finding references
|
|
GLOBAL_ALIST_INIT(reftracker_skip_typecache, init_reftracker_skip_typecache())
|
|
// empty alist we swap with GLOB.reftracker_skip_typecache whenever someone calls toggle_fast_reftracking
|
|
GLOBAL_ALIST_EMPTY(reftracker_skip_typecache_b)
|
|
|
|
/proc/toggle_fast_reftracking()
|
|
var/alist/a = GLOB.reftracker_skip_typecache
|
|
var/alist/b = GLOB.reftracker_skip_typecache_b
|
|
GLOB.reftracker_skip_typecache = b
|
|
GLOB.reftracker_skip_typecache_b = a
|
|
|
|
/proc/init_reftracker_skip_typecache()
|
|
. = alist()
|
|
for(var/base_type in list(
|
|
/icon,
|
|
/matrix,
|
|
/regex,
|
|
/atom/movable/lighting_object, // only contains turf and MA refs
|
|
/atom/movable/mirage_holder,
|
|
/atom/movable/render_step/emissive_blocker,
|
|
/datum/armor,
|
|
/datum/asset_cache_item,
|
|
/datum/book_info,
|
|
/datum/card,
|
|
/datum/chat_payload,
|
|
/datum/comm_log_entry,
|
|
/datum/gas_mixture,
|
|
/datum/greyscale_layer,
|
|
/datum/icon_transformer,
|
|
/datum/instrument_key,
|
|
/datum/movespeed_modifier,
|
|
/datum/painting,
|
|
/datum/paper_input,
|
|
/datum/physiology,
|
|
/datum/plant_gene/reagent,
|
|
/datum/qdel_item,
|
|
/datum/stack_recipe,
|
|
/datum/tlv,
|
|
/datum/universal_icon,
|
|
/datum/weakref,
|
|
/datum/z_pillar,
|
|
/obj/effect/abstract/z_holder,
|
|
// stuff below isn't 100% guaranteed to be ref-free, but they're prolly not an issue
|
|
/turf/closed/mineral,
|
|
/turf/open/lava,
|
|
/turf/open/misc/asteroid,
|
|
/turf/open/openspace,
|
|
/turf/open/space,
|
|
/obj/structure/flora, // icebox and such has a LOT of these
|
|
/datum/chatmessage,
|
|
/datum/lighting_corner,
|
|
/datum/log_entry, // hopefully nobody's silly enough to accidentally pass a reference to these... right???
|
|
/datum/reagent/consumable/nutriment,
|
|
))
|
|
for(var/type in typesof(base_type))
|
|
.[type] = TRUE
|
|
#endif
|
|
|
|
/datum/proc/find_references(references_to_clear = INFINITY)
|
|
if(usr?.client)
|
|
if(tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes")
|
|
return
|
|
|
|
src.references_to_clear = references_to_clear
|
|
//this keeps the garbage collector from failing to collect objects being searched for in here
|
|
SSgarbage.can_fire = FALSE
|
|
|
|
_search_references()
|
|
//restart the garbage collector
|
|
SSgarbage.can_fire = TRUE
|
|
SSgarbage.update_nextfire(reset_time = TRUE)
|
|
|
|
/datum/proc/_search_references()
|
|
log_reftracker("Beginning search for references to a [type], looking for [references_to_clear] refs.")
|
|
|
|
var/starting_time = world.time
|
|
//Time to search the whole game for our ref
|
|
DoSearchVar(GLOB, "GLOB", starting_time) //globals
|
|
log_reftracker("Finished searching globals")
|
|
if(src.references_to_clear == 0)
|
|
return
|
|
|
|
//Yes we do actually need to do this. The searcher refuses to read weird lists
|
|
//And global.vars is a really weird list
|
|
var/global_vars = list()
|
|
for(var/key in global.vars)
|
|
global_vars[key] = global.vars[key]
|
|
|
|
DoSearchVar(global_vars, "Native Global", starting_time)
|
|
log_reftracker("Finished searching native globals")
|
|
if(src.references_to_clear == 0)
|
|
return
|
|
|
|
#ifdef FAST_REFERENCE_TRACKING
|
|
var/alist/skip_types = GLOB.reftracker_skip_typecache
|
|
#endif
|
|
|
|
for(var/datum/thing in world) //atoms (don't beleive its lies)
|
|
#ifdef FAST_REFERENCE_TRACKING
|
|
if(skip_types[thing.type])
|
|
continue
|
|
#endif
|
|
DoSearchVar(thing, "World -> [thing.type]", starting_time)
|
|
if(src.references_to_clear == 0)
|
|
break
|
|
log_reftracker("Finished searching atoms")
|
|
if(src.references_to_clear == 0)
|
|
return
|
|
|
|
for(var/datum/thing) //datums
|
|
#ifdef FAST_REFERENCE_TRACKING
|
|
if(skip_types[thing.type])
|
|
continue
|
|
#endif
|
|
DoSearchVar(thing, "Datums -> [thing.type]", starting_time)
|
|
if(src.references_to_clear == 0)
|
|
break
|
|
log_reftracker("Finished searching datums")
|
|
if(src.references_to_clear == 0)
|
|
return
|
|
|
|
//Warning, attempting to search clients like this will cause crashes if done on live. Watch yourself
|
|
#ifndef REFERENCE_DOING_IT_LIVE
|
|
for(var/client/thing) //clients
|
|
DoSearchVar(thing, "Clients -> [thing.type]", starting_time)
|
|
if(src.references_to_clear == 0)
|
|
break
|
|
log_reftracker("Finished searching clients")
|
|
if(src.references_to_clear == 0)
|
|
return
|
|
#endif
|
|
|
|
log_reftracker("Completed search for references to a [type].")
|
|
|
|
/datum/proc/DoSearchVar(potential_container, container_name, search_time, recursion_count, is_special_list)
|
|
if(recursion_count >= REFSEARCH_RECURSE_LIMIT)
|
|
log_reftracker("Recursion limit reached. [container_name]")
|
|
return
|
|
|
|
if(references_to_clear == 0)
|
|
return
|
|
|
|
//Check each time you go down a layer. This makes it a bit slow, but it won't effect the rest of the game at all
|
|
#ifndef FIND_REF_NO_CHECK_TICK
|
|
CHECK_TICK
|
|
#endif
|
|
|
|
if(isdatum(potential_container))
|
|
var/datum/datum_container = potential_container
|
|
if(datum_container.last_find_references == search_time)
|
|
return
|
|
|
|
datum_container.last_find_references = search_time
|
|
var/list/vars_list = datum_container.vars
|
|
|
|
var/is_atom = FALSE
|
|
var/is_area = FALSE
|
|
if(isatom(datum_container))
|
|
is_atom = TRUE
|
|
if(isarea(datum_container))
|
|
is_area = TRUE
|
|
for(var/varname in vars_list)
|
|
var/variable = vars_list[varname]
|
|
if(islist(variable))
|
|
//Fun fact, vis_locs don't count for references
|
|
if(varname == "vars" || (is_atom && (varname == "vis_locs" || varname == "overlays" || varname == "underlays" || varname == "filters" || varname == "verbs" || (is_area && varname == "contents"))))
|
|
continue
|
|
// We do this after the varname check to avoid area contents (reading it incures a world loop's worth of cost)
|
|
if(!length(variable))
|
|
continue
|
|
DoSearchVar(variable,\
|
|
"[container_name] [datum_container.ref_search_details()] -> [varname] (list)",\
|
|
search_time,\
|
|
recursion_count + 1,\
|
|
/*is_special_list = */ is_atom && (varname == "contents" || varname == "vis_contents" || varname == "locs"))
|
|
else if(variable == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
if(SSgarbage.should_save_refs)
|
|
if(!found_refs)
|
|
found_refs = list()
|
|
found_refs[varname] = TRUE
|
|
continue //End early, don't want these logging
|
|
else
|
|
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
|
|
#else
|
|
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
|
|
#endif
|
|
references_to_clear -= 1
|
|
if(references_to_clear == 0)
|
|
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
|
|
return
|
|
continue
|
|
|
|
else if(islist(potential_container))
|
|
var/list/potential_cache = potential_container
|
|
var/is_alist = isalist(potential_cache)
|
|
for(var/element_in_list in potential_cache)
|
|
//Check normal sublists
|
|
if(islist(element_in_list))
|
|
if(length(element_in_list))
|
|
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", search_time, recursion_count + 1)
|
|
//Check normal entrys
|
|
else if(element_in_list == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
if(SSgarbage.should_save_refs)
|
|
if(!found_refs)
|
|
found_refs = list()
|
|
found_refs[potential_cache] = TRUE
|
|
continue
|
|
else
|
|
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
|
|
#else
|
|
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
|
|
#endif
|
|
|
|
// This is dumb as hell I'm sorry
|
|
// I don't want the garbage subsystem to count as a ref for the purposes of this number
|
|
// If we find all other refs before it I want to early exit, and if we don't I want to keep searching past it
|
|
var/ignore_ref = FALSE
|
|
var/list/queues = SSgarbage.queues
|
|
for(var/list/queue in queues)
|
|
if(potential_cache in queue)
|
|
ignore_ref = TRUE
|
|
break
|
|
if(ignore_ref)
|
|
log_reftracker("[container_name] does not count as a ref for our count")
|
|
else
|
|
references_to_clear -= 1
|
|
if(references_to_clear == 0)
|
|
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
|
|
return
|
|
|
|
if((!isnum(element_in_list) || is_alist) && !is_special_list)
|
|
// This exists to catch an error that throws when we access a special list
|
|
// is_special_list is a hint, it can be wrong
|
|
try
|
|
var/assoc_val = potential_cache[element_in_list]
|
|
//Check assoc sublists
|
|
if(islist(assoc_val))
|
|
if(length(assoc_val))
|
|
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", search_time, recursion_count + 1)
|
|
//Check assoc entry
|
|
else if(assoc_val == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
if(SSgarbage.should_save_refs)
|
|
if(!found_refs)
|
|
found_refs = list()
|
|
found_refs[potential_cache] = TRUE
|
|
continue
|
|
else
|
|
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
|
|
#else
|
|
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
|
|
#endif
|
|
references_to_clear -= 1
|
|
if(references_to_clear == 0)
|
|
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
|
|
return
|
|
catch
|
|
// So if it goes wrong we kill it
|
|
is_special_list = TRUE
|
|
log_reftracker("Curiosity: [container_name] lead to an error when acessing [element_in_list], what is it?")
|
|
|
|
#undef REFSEARCH_RECURSE_LIMIT
|
|
#endif
|
|
|
|
// Kept outside the ifdef so overrides are easy to implement
|
|
|
|
/// Return info about us for reference searching purposes
|
|
/// Will be logged as a representation of this datum if it's a part of a search chain
|
|
/datum/proc/ref_search_details()
|
|
return text_ref(src)
|
|
|
|
/datum/callback/ref_search_details()
|
|
return "[text_ref(src)] (obj: [object] proc: [delegate] args: [json_encode(arguments)] user: [user?.resolve() || "null"])"
|