From c464d8fcdf43ac90333872a0a7271c100bdc415a Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 30 Oct 2022 00:09:15 -0700 Subject: [PATCH] Optimizes qdel related things (slight init time savings) (#70729) * Moves spawners and decals to a different init/delete scheme Rather then fully creating and then immediately deleting these things, we instead do the bare minimum. This is faster, if in theory more fragile. We should be safe since any errors should be caught in compile since this is very close to a "static" action. It does mean these atoms cannot use signals, etc. * Potentially saves init time, mostly cleans up a silly pattern We use sleeps and INVOKE_ASYNC to ensure that handing back turfs doesn't block a space reservation, but this by nature consumes up to the threshold and a bit more of whatever working block we were in. This is silly. Should just be a subsystem, so I made it one, with support for awaiting its finish if you want to * Optimizes garbage/proc/Queue slightly Queue takes about 1.6 seconds to process 26k items right now. The MASSIVE majority of this time is spent on using \ref This is because \ref returns a string, and that string requires being inserted into the global cache of strings we store What I'm doing is caching the result of ANY \ref on the datum it's applied to. This ensures previous uses will never decay from the string tree. This saves about 0.2 seconds of init --- code/__DEFINES/is_helpers.dm | 2 ++ code/__DEFINES/misc.dm | 7 +++++ code/__DEFINES/typeids.dm | 2 +- code/__HELPERS/icons.dm | 6 ++--- code/__HELPERS/unsorted.dm | 12 +++++---- code/controllers/subsystem/garbage.dm | 8 +++--- code/controllers/subsystem/statpanel.dm | 15 +++++------ code/controllers/subsystem/timer.dm | 4 +-- code/controllers/subsystem/vis_overlays.dm | 2 +- code/datums/datum.dm | 5 ++++ code/datums/position_point_vector.dm | 27 ++++++++++++++----- code/game/gamemodes/dynamic/dynamic.dm | 22 +++++++-------- code/game/machinery/airlock_cycle_control.dm | 8 +++--- code/game/objects/effects/decals/decal.dm | 26 ++++++++++++++---- code/game/objects/effects/misc.dm | 17 ++++++++++++ .../objects/effects/spawners/bombspawner.dm | 2 -- code/game/objects/effects/spawners/bundle.dm | 3 +-- .../game/objects/effects/spawners/lootdrop.dm | 3 +-- .../objects/effects/spawners/structure.dm | 7 ++--- code/game/objects/effects/spawners/traps.dm | 3 +-- .../effects/spawners/xeno_egg_delivery.dm | 3 +-- code/game/objects/items/stacks/stack.dm | 2 +- code/modules/admin/admin.dm | 2 +- code/modules/admin/sound_emitter.dm | 12 ++++----- .../view_variables/reference_tracking.dm | 10 +++---- code/modules/antagonists/borer/borer.dm | 12 ++++----- code/modules/events/holiday/xmas.dm | 6 ++--- code/modules/language/language_holder.dm | 2 +- code/modules/mob/say_vr.dm | 12 +++------ 29 files changed, 144 insertions(+), 98 deletions(-) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 4dc29d360b82..b824bd2a17b1 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -4,6 +4,8 @@ #define isatom(A) (isloc(A)) +#define isdatum(thing) (istype(thing, /datum)) + #define isweakref(D) (istype(D, /datum/weakref)) //Turfs diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 03796c87e897..e8975a1a6653 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -149,6 +149,13 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) //subtypesof(), typesof() without the parent path #define subtypesof(typepath) (typesof(typepath) - typepath) +/// Takes a datum as input, returns its ref string, or a cached version of it +/// This allows us to cache \ref creation, which ensures it'll only ever happen once per datum, saving string tree time +/// It is slightly less optimal then a []'d datum, but the cost is massively outweighed by the potential savings +/// It will only work for datums mind, for datum reasons +/// : because of the embedded typecheck +#define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]")) + //Gets the turf this atom inhabits #define get_turf(A) (get_step(A, 0)) diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm index 3cf1b16e000b..5329164229d0 100644 --- a/code/__DEFINES/typeids.dm +++ b/code/__DEFINES/typeids.dm @@ -3,6 +3,6 @@ #define TYPEID_NORMAL_LIST "f" //helper macros #define GET_TYPEID(ref) (((length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7))) -#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST) +#define IS_NORMAL_LIST(L) (GET_TYPEID(text_ref(L)) == TYPEID_NORMAL_LIST) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 126d93fe352a..38e540e996b9 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1198,7 +1198,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico if(isicon(icon) && isfile(icon)) //icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects, ///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want - var/icon_ref = "\ref[icon]" + var/icon_ref = text_ref(icon) var/locate_icon_string = "[locate(icon_ref)]" icon_path = locate_icon_string @@ -1209,7 +1209,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico // the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi" var/rsc_ref = fcopy_rsc(icon) - var/icon_ref = "\ref[rsc_ref]" + var/icon_ref = text_ref(rsc_ref) var/icon_path_string = "[locate(icon_ref)]" @@ -1219,7 +1219,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico var/rsc_ref = fcopy_rsc(icon) //if its the text path of an existing dmi file, the rsc reference returned by fcopy_rsc() will be stringifiable to a dmi path - var/rsc_ref_ref = "\ref[rsc_ref]" + var/rsc_ref_ref = text_ref(rsc_ref) var/rsc_ref_string = "[locate(rsc_ref_ref)]" icon_path = rsc_ref_string diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index ea9ceee0f417..ee495ee917d2 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1363,11 +1363,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}" -// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. -// If it ever becomes necesary to get a more performant REF(), this lies here in wait -// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]") +/** + * \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. + * If it ever becomes necesary to get a more performant REF(), this lies here in wait + * #define REF(thing) (thing && isdatum(thing) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : text_ref(thing)) +**/ /proc/REF(input) - if(istype(input, /datum)) + if(isdatum(input)) var/datum/thing = input if(thing.datum_flags & DF_USE_TAG) if(!thing.tag) @@ -1375,7 +1377,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) thing.datum_flags &= ~DF_USE_TAG else return "\[[url_encode(thing.tag)]\]" - return "\ref[input]" + return text_ref(input) // Makes a call in the context of a different usr // Use sparingly diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 895a8c1685fc..b362a7ed4e62 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -221,7 +221,7 @@ SUBSYSTEM_DEF(garbage) var/type = D.type var/datum/qdel_item/I = items[type] - log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --") + log_world("## TESTING: GC: -- [text_ref(D)] | [type] was unable to be GC'd --") #ifdef TESTING for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage var/client/admin = c @@ -258,7 +258,7 @@ SUBSYSTEM_DEF(garbage) return var/queue_time = world.time - var/refid = "\ref[D]" + var/refid = text_ref(D) if (D.gc_destroyed <= 0) D.gc_destroyed = queue_time @@ -271,7 +271,7 @@ SUBSYSTEM_DEF(garbage) ++delslasttick ++totaldels var/type = D.type - var/refID = "\ref[D]" + var/refID = text_ref(D) var/datum/qdel_item/I = items[type] if (!force && I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG) @@ -389,7 +389,7 @@ SUBSYSTEM_DEF(garbage) D.find_references() if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. SSgarbage.Queue(D) - SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE + SSgarbage.reference_find_on_fail[text_ref(D)] = TRUE #endif else #ifdef TESTING diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index ad13009760a0..1b844f168cf9 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -153,17 +153,16 @@ SUBSYSTEM_DEF(statpanels) list("CPU:", world.cpu), list("Instances:", "[num2text(world.contents.len, 10)]"), list("World Time:", "[world.time]"), - list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"), - list("[config]:", config.stat_entry(), "\ref[config]"), + list("Globals:", GLOB.stat_entry(), text_ref(GLOB)), + list("[config]:", config.stat_entry(), text_ref(config)), list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)"), - list("Master Controller:", Master.stat_entry(), "\ref[Master]"), - list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"), + list("Master Controller:", Master.stat_entry(), text_ref(Master)), + list("Failsafe Controller:", Failsafe.stat_entry(), text_ref(Failsafe)), list("","") ) - for(var/ss in Master.subsystems) - var/datum/controller/subsystem/sub_system = ss - mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]") - mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]") + for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems) + mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), text_ref(sub_system)) + mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", text_ref(GLOB.cameranet)) mc_data_encoded = url_encode(json_encode(mc_data)) /atom/proc/remove_from_cache() diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index a37f7e1c0896..176f91cf5808 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -511,8 +511,8 @@ SUBSYSTEM_DEF(timer) /datum/timedevent/proc/bucketJoin() // Generate debug-friendly name for timer var/static/list/bitfield_flags = list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP") - name = "Timer: [id] (\ref[src]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield_to_list(flags, bitfield_flags), ", ")], \ - callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), \ + name = "Timer: [id] ([text_ref(src)]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield_to_list(flags, bitfield_flags), ", ")], \ + callBack: [text_ref(callBack)], callBack.object: [callBack.object][text_ref(callBack.object)]([getcallingtype()]), \ callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""]), source: [source]" if (bucket_joined) diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index a4b0fccae437..6d134610f9f3 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -42,7 +42,7 @@ SUBSYSTEM_DEF(vis_overlays) else overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) overlay.cache_expiration = -1 - var/cache_id = "\ref[overlay]@{[world.time]}" + var/cache_id = "[text_ref(overlay)]@{[world.time]}" vis_overlay_cache[cache_id] = overlay . = overlay if(overlay == null) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index e2f478ba7834..73aab2fb8ca8 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -40,6 +40,11 @@ /// Datum level flags var/datum_flags = NONE + /// A cached version of our \ref + /// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings) + /// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled + var/cached_ref + /// A weak reference to another datum var/datum/weakref/weak_reference diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm index 07fe0ed7652f..9675c337fcc8 100644 --- a/code/datums/position_point_vector.dm +++ b/code/datums/position_point_vector.dm @@ -22,7 +22,8 @@ /proc/angle_between_points(datum/point/a, datum/point/b) return ATAN2((b.y - a.y), (b.x - a.x)) -/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess. +/// For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess. +/datum/position var/x = 0 var/y = 0 var/z = 0 @@ -66,7 +67,8 @@ /datum/position/proc/return_point() return new /datum/point(src) -/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP! +/// A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP! +/datum/point var/x = 0 var/y = 0 var/z = 0 @@ -80,7 +82,8 @@ p.z = z return p -/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom. +/// First argument can also be a /datum/position or /atom. +/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) if(istype(_x, /datum/position)) var/datum/position/P = _x _x = P.x @@ -107,7 +110,7 @@ /datum/point/proc/debug_out() var/turf/T = return_turf() - return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]" + return "[text_ref(src)] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]" /datum/point/proc/move_atom_to_src(atom/movable/AM) AM.forceMove(return_turf()) @@ -130,10 +133,13 @@ return MODULUS(y, world.icon_size) - 16 - 1 /datum/point/vector - var/speed = 32 //pixels per iteration + /// Pixels per iteration + var/speed = 32 var/iteration = 0 var/angle = 0 - var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step. + /// Calculated x movement amounts to prevent having to do trig every step. + var/mpx = 0 + /// Calculated y movement amounts to prevent having to do trig every step. var/mpy = 0 var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location(). var/starting_y = 0 @@ -151,6 +157,15 @@ starting_y = y starting_z = z +/// Same effect as initiliaze_location, but without setting the starting_x/y/z +/datum/point/vector/proc/set_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0) + if(!isnull(tile_x)) + x = ((tile_x - 1) * world.icon_size) + world.icon_size * 0.5 + p_x + 1 + if(!isnull(tile_y)) + y = ((tile_y - 1) * world.icon_size) + world.icon_size * 0.5 + p_y + 1 + if(!isnull(tile_z)) + z = tile_z + /datum/point/vector/copy_to(datum/point/vector/v = new) ..(v) v.speed = speed diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 3b139bba78e9..81cd538a7e45 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -111,22 +111,22 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /datum/game_mode/dynamic/admin_panel() var/list/dat = list("Game Mode Panel

Game Mode Panel

") - dat += "Dynamic Mode \[VV\]\[Refresh\]
" + dat += "Dynamic Mode \[VV\]\[Refresh\]
" dat += "Threat Level: [threat_level]
" - dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
" + dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
" dat += "
" dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
" dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
" - dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
" - dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
" - dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
" - dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]" + dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
" + dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
" + dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
" + dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]" dat += "
" - dat += "\[Force Next Latejoin Ruleset\]
" + dat += "\[Force Next Latejoin Ruleset\]
" if (forced_latejoin_rule) - dat += {"-> [forced_latejoin_rule.name] <-
"} - dat += "\[Execute Midround Ruleset\]
" + dat += {"-> [forced_latejoin_rule.name] <-
"} + dat += "\[Execute Midround Ruleset\]
" dat += "
" dat += "Executed rulesets: " if (executed_rules.len > 0) @@ -136,8 +136,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) else dat += "none.
" dat += "
Injection Timers: ([get_injection_chance(TRUE)]% chance)
" - dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
" - dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
" + dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
" + dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
" usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") /datum/game_mode/dynamic/Topic(href, href_list) diff --git a/code/game/machinery/airlock_cycle_control.dm b/code/game/machinery/airlock_cycle_control.dm index 0b35bedebd05..76094e803cd3 100644 --- a/code/game/machinery/airlock_cycle_control.dm +++ b/code/game/machinery/airlock_cycle_control.dm @@ -167,7 +167,7 @@ var/maxpressure = (exterior_pressure && (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)) ? exterior_pressure : interior_pressure var/pressure_bars = round(pressure / maxpressure * 5 + 0.01) - var/new_overlays_hash = "[pressure_bars]-[cyclestate]-[buildstage]-[panel_open]-[machine_stat]-[shorted]-[locked]-\ref[vis_target]" + var/new_overlays_hash = "[pressure_bars]-[cyclestate]-[buildstage]-[panel_open]-[machine_stat]-[shorted]-[locked]-[text_ref(vis_target)]" if(use_hash && new_overlays_hash == overlays_hash) return ..() overlays_hash = new_overlays_hash @@ -645,7 +645,7 @@ "airlocks" = list(), "skip_timer" = (world.time - skip_timer), "skip_delay" = skip_delay, - "vis_target" = "\ref[vis_target]" + "vis_target" = "[text_ref(vis_target)]" ) if((locked && !user.has_unlimited_silicon_privilege) || (user.has_unlimited_silicon_privilege && aidisabled)) @@ -661,7 +661,7 @@ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V data["vents"] += list(list( "role" = vents[vent], - "vent_id" = "\ref[vent]", + "vent_id" = "[text_ref(vent)]", "name" = vent.name )) for(var/A in airlocks) @@ -683,7 +683,7 @@ data["airlocks"] += list(list( "role" = airlocks[airlock], - "airlock_id" = "\ref[airlock]", + "airlock_id" = "[text_ref(airlock)]", "name" = airlock.name, "access" = access_str )) diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index e375cfd1117e..eb5be990380f 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -46,15 +46,31 @@ var/detail_overlay var/detail_color -/obj/effect/turf_decal/Initialize() - ..() - return INITIALIZE_HINT_QDEL +// This is with the intent of optimizing mapload +// See spawners for more details since we use the same pattern +// Basically rather then creating and deleting ourselves, why not just do the bare minimum? +/obj/effect/turf_decal/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 -/obj/effect/turf_decal/ComponentInitialize() - . = ..() var/turf/T = loc if(!istype(T)) //you know this will happen somehow CRASH("Turf decal initialized in an object/nullspace") T.AddElement(/datum/element/decal, icon, icon_state, dir, FALSE, color, null, null, alpha, FALSE) if(detail_overlay) T.AddElement(/datum/element/decal, icon, detail_overlay, dir, FALSE, detail_color, null, null, alpha, appearance_flags) + return INITIALIZE_HINT_QDEL + +/obj/effect/turf_decal/Destroy(force) + SHOULD_CALL_PARENT(FALSE) +#ifdef UNIT_TESTS +// If we don't do this, turf decals will end up stacking up on a tile, and break the overlay limit +// I hate it too bestie + if(GLOB.running_create_and_destroy) + var/turf/T = loc + T.RemoveElement(/datum/element/decal, icon, icon_state, dir, null, null, alpha, color, null, FALSE, null) +#endif + moveToNullspace() + return QDEL_HINT_QUEUE diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 6d5f840fcc68..b21c0b7073d5 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -21,6 +21,23 @@ /obj/effect/spawner name = "object spawner" +// Brief explanation: +// Rather then setting up and then deleting spawners, we block all atomlike setup +// and do the absolute bare minimum +// This is with the intent of optimizing mapload +/obj/effect/spawner/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + + return INITIALIZE_HINT_QDEL + +/obj/effect/spawner/Destroy(force) + SHOULD_CALL_PARENT(FALSE) + moveToNullspace() + return QDEL_HINT_QUEUE + /obj/effect/list_container name = "list container" diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index 914b910d9830..e1df4ff4ad18 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -37,8 +37,6 @@ V.update_appearance() - return INITIALIZE_HINT_QDEL - /obj/effect/spawner/newbomb/timer/syndicate/Initialize() temp_p = (OPTIMAL_TEMP_K_PLA_BURN_SCALE(pressure_p, pressure_o, temp_o)/2 + OPTIMAL_TEMP_K_PLA_BURN_RATIO(pressure_p, pressure_o, temp_o)/2) - T0C . = ..() diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm index 41faf88745b2..beb4a809ad03 100644 --- a/code/game/objects/effects/spawners/bundle.dm +++ b/code/game/objects/effects/spawners/bundle.dm @@ -7,11 +7,10 @@ var/list/items /obj/effect/spawner/bundle/Initialize(mapload) - ..() + . = ..() if(items && items.len) for(var/path in items) new path(loc) - return INITIALIZE_HINT_QDEL /obj/effect/spawner/bundle/costume/chicken name = "chicken costume spawner" diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index bedf2c894b03..04e7d81fd7dd 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -8,7 +8,7 @@ var/fan_out_items = FALSE //Whether the items should be distributed to offsets 0,1,-1,2,-2,3,-3.. This overrides pixel_x/y on the spawner itself /obj/effect/spawner/lootdrop/Initialize(mapload) - ..() + . = ..() if(loot && loot.len) var/loot_spawned = 0 while((lootcount-loot_spawned) && loot.len) @@ -31,7 +31,6 @@ else break // WS edit - Support spawn weights of 0 in loot tables and ruins loot_spawned++ - return INITIALIZE_HINT_QDEL /obj/effect/spawner/lootdrop/donkpockets name = "donk pocket box spawner" diff --git a/code/game/objects/effects/spawners/structure.dm b/code/game/objects/effects/spawners/structure.dm index 9ce3411cc93a..ec893399630b 100644 --- a/code/game/objects/effects/spawners/structure.dm +++ b/code/game/objects/effects/spawners/structure.dm @@ -15,11 +15,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/spawner/structure) /obj/effect/spawner/structure/Initialize() . = ..() - if(spawn_list && spawn_list.len) - for(var/I in spawn_list) - new I(get_turf(src)) - return INITIALIZE_HINT_QDEL - + for(var/spawn_type in spawn_list) + new spawn_type(loc) //normal windows diff --git a/code/game/objects/effects/spawners/traps.dm b/code/game/objects/effects/spawners/traps.dm index 731b4efc1d98..0409d9944b9b 100644 --- a/code/game/objects/effects/spawners/traps.dm +++ b/code/game/objects/effects/spawners/traps.dm @@ -4,7 +4,6 @@ icon_state = "trap_rand" /obj/effect/spawner/trap/Initialize(mapload) - ..() + . = ..() var/new_type = pick(subtypesof(/obj/structure/trap) - typesof(/obj/structure/trap/ctf)) new new_type(get_turf(src)) - return INITIALIZE_HINT_QDEL diff --git a/code/game/objects/effects/spawners/xeno_egg_delivery.dm b/code/game/objects/effects/spawners/xeno_egg_delivery.dm index d0e99d0f9036..99eac4828932 100644 --- a/code/game/objects/effects/spawners/xeno_egg_delivery.dm +++ b/code/game/objects/effects/spawners/xeno_egg_delivery.dm @@ -5,7 +5,7 @@ var/announcement_time = 1200 /obj/effect/spawner/xeno_egg_delivery/Initialize(mapload) - ..() + . = ..() var/turf/T = get_turf(src) new /obj/structure/alien/egg(T) @@ -16,4 +16,3 @@ log_game("An alien egg has been delivered to [AREACOORD(T)]") var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(T, TRUE)]. Remember to follow all safety precautions when dealing with the specimen." SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/_addtimer, CALLBACK(GLOBAL_PROC, /proc/print_command_report, message), announcement_time)) - return INITIALIZE_HINT_QDEL diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index ec750eb66aca..0811e39fbe67 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -156,7 +156,7 @@ "res_amount" = R.res_amount, "max_res_amount" = R.max_res_amount, "req_amount" = R.req_amount, - "ref" = "\ref[R]", + "ref" = text_ref(R), ) /** diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index a530012270ae..82cb857576c1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -437,7 +437,7 @@ dat += "(Force Roundstart Rulesets)
" if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) - dat += {"-> [rule.name] <-
"} + dat += {"-> [rule.name] <-
"} dat += "(Clear Rulesets)
" dat += "(Dynamic mode options)
" dat += "
" diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm index 2c930034967f..bdf2a4e6aa34 100644 --- a/code/modules/admin/sound_emitter.dm +++ b/code/modules/admin/sound_emitter.dm @@ -58,16 +58,16 @@ /obj/effect/sound_emitter/proc/edit_emitter(mob/user) var/dat = "" - dat += "Label: [maptext ? maptext : "No label set!"]
" + dat += "Label: [maptext ? maptext : "No label set!"]
" dat += "
" - dat += "Sound File: [sound_file ? sound_file : "No file chosen!"]
" - dat += "Volume: [sound_volume]%
" + dat += "Sound File: [sound_file ? sound_file : "No file chosen!"]
" + dat += "Volume: [sound_volume]%
" dat += "
" - dat += "Mode: [motus_operandi]
" + dat += "Mode: [motus_operandi]
" if(motus_operandi != SOUND_EMITTER_LOCAL) - dat += "Range: [emitter_range][emitter_range == SOUND_EMITTER_RADIUS ? "[play_radius]-tile radius" : ""]
" + dat += "Range: [emitter_range][emitter_range == SOUND_EMITTER_RADIUS ? "[play_radius]-tile radius" : ""]
" dat += "
" - dat += "Play Sound (interrupts other sound emitter sounds)" + dat += "Play Sound (interrupts other sound emitter sounds)" var/datum/browser/popup = new(user, "emitter", "", 500, 600) popup.set_content(dat) popup.open() diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index 69d3a5d1541b..a9a84986416d 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -106,11 +106,11 @@ found_refs[varname] = TRUE continue //End early, don't want these logging #endif - log_reftracker("Found [type] \ref[src] in [datum_container.type]'s \ref[datum_container] [varname] var. [container_name]") + log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [text_ref(datum_container)] [varname] var. [container_name]") continue if(islist(variable)) - DoSearchVar(variable, "[container_name] \ref[datum_container] -> [varname] (list)", recursive_limit - 1, search_time) + DoSearchVar(variable, "[container_name] [text_ref(datum_container)] -> [varname] (list)", recursive_limit - 1, search_time) else if(islist(potential_container)) var/normal = IS_NORMAL_LIST(potential_container) @@ -126,7 +126,7 @@ found_refs[potential_cache] = TRUE continue //End early, don't want these logging #endif - log_reftracker("Found [type] \ref[src] in list [container_name].") + log_reftracker("Found [type] [text_ref(src)] in list [container_name].") continue var/assoc_val = null @@ -139,7 +139,7 @@ found_refs[potential_cache] = TRUE continue //End early, don't want these logging #endif - log_reftracker("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]") + log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]") continue //We need to run both of these checks, since our object could be hiding in either of them //Check normal sublists @@ -153,7 +153,7 @@ thing_to_del.qdel_and_find_ref_if_fail(force) /datum/proc/qdel_and_find_ref_if_fail(force = FALSE) - SSgarbage.reference_find_on_fail["\ref[src]"] = TRUE + SSgarbage.reference_find_on_fail[text_ref(src)] = TRUE qdel(src, force) #endif diff --git a/code/modules/antagonists/borer/borer.dm b/code/modules/antagonists/borer/borer.dm index 4fc5a6aab8f1..ca9b6af1b106 100644 --- a/code/modules/antagonists/borer/borer.dm +++ b/code/modules/antagonists/borer/borer.dm @@ -136,7 +136,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3) . = ..() generation = gen if(is_team_borer) - notify_ghosts("A cortical borer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK) + notify_ghosts("A cortical borer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK) var/numeral = rand(1000, 9999) real_name = "Cortical Borer [numeral]" truename = "[borer_names[min(generation, borer_names.len)]] [numeral]" @@ -200,7 +200,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3) chemicals -= C.chemuse log_game("[src]/([src.ckey]) has injected [C.chemname] ([C.chem]) into their host [victim]/([victim.ckey])") - src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals") + src << output(chemicals, "ViewBorer[text_ref(src)]Chems.browser:update_chemicals") ..() @@ -235,7 +235,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3) if(statpanel("Status")) stat(null, "Chemicals: [chemicals]") - src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals") + src << output(chemicals, "ViewBorer[text_ref(src)]Chems.browser:update_chemicals") /mob/living/simple_animal/borer/verb/Communicate() set category = "Borer" @@ -484,13 +484,13 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3) for(var/datum in typesof(/datum/borer_chem)) var/datum/borer_chem/C = new datum() if(C.chem) - content += "[C.chemname] ([C.quantity]u, takes [C.chemuse] chemical)

[C.chem_desc]

" + content += "[C.chemname] ([C.quantity]u, takes [C.chemuse] chemical)

[C.chem_desc]

" content += "" var/html = get_html_template(content) - usr << browse(null, "window=ViewBorer\ref[src]Chems;size=600x800") - usr << browse(html, "window=ViewBorer\ref[src]Chems;size=600x800") + usr << browse(null, "window=ViewBorer[text_ref(src)]Chems;size=600x800") + usr << browse(html, "window=ViewBorer[text_ref(src)]Chems;size=600x800") return diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index f1a36affcd3b..f38d21b868c4 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -49,15 +49,13 @@ var/festive_tree = /obj/structure/flora/tree/pine/xmas var/christmas_tree = /obj/structure/flora/tree/pine/xmas/presents -/obj/effect/spawner/xmastree/Initialize() - ..() +/obj/effect/spawner/xmastree/Initialize(mapload) + . = ..() if((CHRISTMAS in SSevents.holidays) && christmas_tree) new christmas_tree(get_turf(src)) else if((FESTIVE_SEASON in SSevents.holidays) && festive_tree) new festive_tree(get_turf(src)) - return INITIALIZE_HINT_QDEL - /obj/effect/spawner/xmastree/rdrod name = "festivus pole spawner" festive_tree = /obj/structure/festivus diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index 1f42ec424706..61570535cbbf 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -55,7 +55,7 @@ Key procs /// Initializes, and copies in the languages from the current atom if available. /datum/language_holder/New(atom/_owner) if(_owner && QDELETED(_owner)) - CRASH("Langauge holder added to a qdeleting thing, what the fuck \ref[_owner]") + CRASH("Langauge holder added to a qdeleting thing, what the fuck [text_ref(_owner)]") owner = _owner if(istype(owner, /datum/mind)) var/datum/mind/M = owner diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index 83bb19a33882..d2e6a4f0dda2 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -10,28 +10,22 @@ set src in usr if(usr != src) - usr << "No." + to_chat(usr, span_warning("You can't set someone else's flavour text!")) var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null) - if(msg) //WS edit - "Cancel" does not clear flavor text + if(msg) msg = copytext(msg, 1, MAX_MESSAGE_LEN) msg = html_encode(msg) flavor_text = msg -/mob/proc/warn_flavor_changed() - if(flavor_text && flavor_text != "") // don't spam people that don't use it! - src << "

OOC Warning:

" - src << "Your flavor text is likely out of date! Change" - /mob/proc/print_flavor_text() if(flavor_text && flavor_text != "") var/msg = replacetext(flavor_text, "\n", " ") if(length(msg) <= 100) return "[msg]" else - return "[copytext(msg, 1, 97)]... More..." - + return "[copytext(msg, 1, 97)]... More..." /mob/proc/get_top_level_mob() if(istype(src.loc,/mob)&&src.loc!=src)