From c0d2b555a2fc2b133b03031fd9e659c405ec485e Mon Sep 17 00:00:00 2001 From: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:20:24 -0500 Subject: [PATCH] VV ports + fixes neon carpet (#810) * VV Upgrades (#78948) * Makes special byond lists display properly * Makes images get a preview in the header * Makes filters display properly * Make variable value display a bit more robust to errors * Kills single char vars :cl: admin: VV can now display the contents of special byond lists like filters, or client.images admin: VV on images now displays the image in the header admin: VV can now display filters and includes their type /:cl: * Always contracts lists when VVing GLOB (#76091) This takes render times from like 20 seconds to maybe 2 Most of the time appears to be clientside rn, so the best we could do further would be reducing the amount of shit that actually needs to render So like, removing the E C M buttons (or at least adding a toggle to render them), that sort of thing A glob vv you can actually use ![image](https://github.com/tgstation/tgstation/assets/58055496/d7c29c9a-aa45-4cad-9f38-7131140cab5b) :cl: admin: VV for global vars will now load MUCH faster, in exchange lists are now perma contracted in that particular pane /:cl: * fix neon carpet --------- Co-authored-by: Emmett Gaines Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/__DEFINES/_helpers.dm | 5 + code/__DEFINES/is_helpers.dm | 9 ++ code/__DEFINES/layers.dm | 2 + code/__DEFINES/vv.dm | 5 + code/controllers/globals.dm | 6 + code/datums/elements/decals/_decal.dm | 1 + code/game/turfs/open/floor/fancy_floor.dm | 4 +- .../admin/view_variables/debug_variables.dm | 136 ++++++++++-------- code/modules/admin/view_variables/topic.dm | 5 +- .../admin/view_variables/view_variables.dm | 77 +++++----- 10 files changed, 152 insertions(+), 98 deletions(-) diff --git a/code/__DEFINES/_helpers.dm b/code/__DEFINES/_helpers.dm index 39f1b497c623..2e4360f2f38f 100644 --- a/code/__DEFINES/_helpers.dm +++ b/code/__DEFINES/_helpers.dm @@ -19,3 +19,8 @@ /// Clears all nulls in a list, returning the amount removed. #define list_clear_nulls(L) ((L):RemoveAll(null)) + +// Refs contain a type id within their string that can be used to identify byond types. +// Custom types that we define don't get a unique id, but this is useful for identifying +// types that don't normally have a way to run istype() on them. +#define TYPEID(thing) copytext(REF(thing), 4, 6) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 9d490ad6041a..36f014ec514d 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -11,6 +11,15 @@ #define isweakref(D) (istype(D, /datum/weakref)) +#define isimage(thing) (istype(thing, /image)) + +GLOBAL_VAR_INIT(magic_appearance_detecting_image, new /image) // appearances are awful to detect safely, but this seems to be the best way ~ninjanomnom +#define isappearance(thing) (!isimage(thing) && !ispath(thing) && istype(GLOB.magic_appearance_detecting_image, thing)) + +// The filters list has the same ref type id as a filter, but isnt one and also isnt a list, so we have to check if the thing has Cut() instead +GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur"))) +#define isfilter(thing) (!hascall(thing, "Cut") && TYPEID(thing) == GLOB.refid_filter) + #define isgenerator(A) (istype(A, /generator)) //Turfs diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 8ca68dee9659..370f9a8a09ff 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -1,6 +1,8 @@ //Defines for atom layers and planes //KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE +//#define FLOAT_PLANE -32767 //For easy recordkeeping; this is a byond define. + //NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE #define LOWEST_EVER_PLANE -200 diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index d2d619f8f977..346c43591921 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -151,3 +151,8 @@ #define VV_HK_TO_OUTFIT_EDITOR "outfit_editor" #define VV_HK_WEAKREF_RESOLVE "weakref_resolve" + +// Flags for debug_variable() that do little things to what we end up rendering + +/// ALWAYS render a reduced list, useful for fuckoff big datums that need to be condensed for the sake of client load +#define VV_ALWAYS_CONTRACT_LIST (1<<0) diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index 8a81069876ee..59294285e053 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -42,6 +42,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) return FALSE return ..() +/datum/controller/global_vars/vv_get_var(var_name) + switch(var_name) + if (NAMEOF(src, vars)) + return debug_variable(var_name, list(), 0, src) + return debug_variable(var_name, vars[var_name], 0, src, display_flags = VV_ALWAYS_CONTRACT_LIST) + /datum/controller/global_vars/Initialize() gvars_datum_init_order = list() gvars_datum_protected_varlist = list(NAMEOF(src, gvars_datum_protected_varlist) = TRUE) diff --git a/code/datums/elements/decals/_decal.dm b/code/datums/elements/decals/_decal.dm index 59d14fc83dad..2434089c6207 100644 --- a/code/datums/elements/decals/_decal.dm +++ b/code/datums/elements/decals/_decal.dm @@ -116,6 +116,7 @@ _layer, _dir ) + pic.plane = _plane pic.color = _color pic.alpha = _alpha return TRUE diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm index 29d8ae2e1327..8ed087301df4 100644 --- a/code/game/turfs/open/floor/fancy_floor.dm +++ b/code/game/turfs/open/floor/fancy_floor.dm @@ -424,8 +424,8 @@ /turf/open/floor/carpet/neon/Initialize(mapload) . = ..() - AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, null, null, alpha, neon_color, smoothing_junction) - AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, EMISSIVE_PLANE, null, emissive_alpha, EMISSIVE_COLOR, smoothing_junction) + AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, null, FLOAT_LAYER, alpha, neon_color, smoothing_junction) + AddElement(/datum/element/decal, neon_icon || icon, neon_icon_state || base_icon_state, dir, EMISSIVE_PLANE, FLOAT_LAYER, emissive_alpha, EMISSIVE_COLOR, smoothing_junction) /turf/open/floor/carpet/neon/simple name = "simple neon carpet" diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index 90bf57d8de72..6535fbb0cf44 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -1,102 +1,120 @@ #define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) /// Get displayed variable in VV variable list -/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value. - var/header - if(D) - if(islist(D)) +/proc/debug_variable(name, value, level, datum/owner, sanitize = TRUE, display_flags = NONE) //if D is a list, name will be index, and value will be assoc value. + if(owner) + if(islist(owner)) var/index = name if (value) - name = D[name] //name is really the index until this line + name = owner[name] //name is really the index until this line else - value = D[name] - header = "
  • ([VV_HREF_TARGET_1V(D, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_REMOVE, "-", index)]) " + value = owner[name] + . = "
  • ([VV_HREF_TARGET_1V(owner, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(owner, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(owner, VV_HK_LIST_REMOVE, "-", index)]) " else - header = "
  • ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_MASSEDIT, "M", name)]) " + . = "
  • ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(owner, VV_HK_BASIC_MASSEDIT, "M", name)]) " else - header = "
  • " + . = "
  • " - var/item var/name_part = VV_HTML_ENCODE(name) - if(level > 0 || islist(D)) //handling keys in assoc lists + if(level > 0 || islist(owner)) //handling keys in assoc lists if(istype(name,/datum)) name_part = "[VV_HTML_ENCODE(name)] [REF(name)]" else if(islist(name)) - var/list/L = name - name_part = " /list ([length(L)]) [REF(name)]" + var/list/list_value = name + name_part = " /list ([length(list_value)]) [REF(name)]" - if (isnull(value)) - item = "[name_part] = null" + . = "[.][name_part] = " - else if (istext(value)) - item = "[name_part] = \"[VV_HTML_ENCODE(value)]\"" + var/item = _debug_variable_value(name, value, level, owner, sanitize, display_flags) - else if (isicon(value)) + return "[.][item]
  • " + +// This is split into a seperate proc mostly to make errors that happen not break things too much +/proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags) + . = "DISPLAY_ERROR" + + if(isnull(value)) + return "null" + + if(istext(value)) + return "\"[VV_HTML_ENCODE(value)]\"" + + if(isicon(value)) #ifdef VARSICON - var/icon/I = icon(value) + var/icon/icon_value = icon(value) var/rnd = rand(1,10000) - var/rname = "tmp[REF(I)][rnd].png" - usr << browse_rsc(I, rname) - item = "[name_part] = ([value]) " + var/rname = "tmp[REF(icon_value)][rnd].png" + usr << browse_rsc(icon_value, rname) + return "([value]) " #else - item = "[name_part] = /icon ([value])" + return "/icon ([value])" #endif - else if (isfile(value)) - item = "[name_part] = '[value]'" + if(isappearance(value)) + var/image/actually_an_appearance = value + return "/appearance (
    icon: [actually_an_appearance.icon]
    state: [actually_an_appearance.icon_state]
    plane: [actually_an_appearance.plane]
    layer: [actually_an_appearance.layer]
    )" - else if(istype(value,/matrix)) // Needs to be before datum - var/matrix/M = value - item = {"[name_part] = -
      - - - - - - -
    [M.a][M.d]0
    [M.b][M.e]0
    [M.c][M.f]1
     
    "} //TODO link to modify_transform wrapper for all matrices - else if (istype(value, /datum)) - var/datum/DV = value - if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it. - item = "[name_part] = [DV] [DV.type] [REF(value)]" - else - item = "[name_part] = [DV.type] [REF(value)]" - if(istype(value,/datum/weakref)) - var/datum/weakref/weakref = value - item += " (Resolve)" + if(isfilter(value)) + var/datum/filter_value = value + return "/filter ([filter_value.type] [REF(filter_value)])" - else if (islist(value)) - var/list/L = value + if(isfile(value)) + return "'[value]'" + + if(isdatum(value)) + var/datum/datum_value = value + return datum_value.debug_variable_value(name, level, owner, sanitize, display_flags) + + if(islist(value) || hascall(value, "Cut")) // Some special lists arent detectable as a list through istype, so we check if it has a list proc instead + var/list/list_value = value var/list/items = list() - if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD))) - for (var/i in 1 to L.len) - var/key = L[i] + if (!(display_flags & VV_ALWAYS_CONTRACT_LIST) && list_value.len > 0 && list_value.len <= (IS_NORMAL_LIST(list_value) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)) + for (var/i in 1 to list_value.len) + var/key = list_value[i] var/val - if (IS_NORMAL_LIST(L) && !isnum(key)) - val = L[key] + if (IS_NORMAL_LIST(list_value) && !isnum(key)) + val = list_value[key] if (isnull(val)) // we still want to display non-null false values, such as 0 or "" val = key key = i items += debug_variable(key, val, level + 1, sanitize = sanitize) - item = "[name_part] = /list ([L.len])" + return "/list ([list_value.len])" else - item = "[name_part] = /list ([L.len])" + return "/list ([list_value.len])" - else if (name in GLOB.bitfields) + if(name in GLOB.bitfields) var/list/flags = list() for (var/i in GLOB.bitfields[name]) if (value & GLOB.bitfields[name][i]) flags += i if(length(flags)) - item = "[name_part] = [VV_HTML_ENCODE(jointext(flags, ", "))]" + return "[VV_HTML_ENCODE(jointext(flags, ", "))]" else - item = "[name_part] = NONE" + return "NONE" else - item = "[name_part] = [VV_HTML_ENCODE(value)]" + return "[VV_HTML_ENCODE(value)]" + +/datum/proc/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + if("[src]" != "[type]") // If we have a name var, let's use it. + return "[src] [type] [REF(src)]" + else + return "[type] [REF(src)]" + +/datum/weakref/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + . = ..() + return "[.] (Resolve)" - return "[header][item]" +/matrix/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + return {" +
      + + + + + + +
    [a][d]0
    [b][e]0
    [c][f]1
     
    "} //TODO link to modify_transform wrapper for all matrices #undef VV_HTML_ENCODE diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index c0ffe2279568..b5ff158aa954 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -11,7 +11,10 @@ else if(islist(target)) vv_do_list(target, href_list) if(href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) + var/datum/vars_target = locate(href_list["Vars"]) + if(href_list["special_varname"]) // Some special vars can't be located even if you have their ref, you have to use this instead + vars_target = vars_target.vars[href_list["special_varname"]] + debug_variables(vars_target) //Stuff below aren't in dropdowns/etc. diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 830979e2f54a..3b3723185a5a 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,4 +1,4 @@ -/client/proc/debug_variables(datum/D in world) +/client/proc/debug_variables(datum/thing in world) set category = "Debug" set name = "View Variables" //set src in world @@ -8,54 +8,58 @@ to_chat(usr, span_danger("You need to be an administrator to access this."), confidential = TRUE) return - if(!D) + if(!thing) return var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) - var/islist = islist(D) - if(!islist && !istype(D)) + var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs + if(!islist && !isdatum(thing)) return var/title = "" - var/refid = REF(D) + var/refid = REF(thing) var/icon/sprite var/hash - var/type = islist? /list : D.type + var/type = islist? /list : thing.type var/no_icon = FALSE - if(istype(D, /atom)) - sprite = getFlatIcon(D) - if(sprite) - hash = md5(sprite) - src << browse_rsc(sprite, "vv[hash].png") - else + if(isatom(thing)) + sprite = getFlatIcon(thing) + if(!sprite) no_icon = TRUE - title = "[D] ([REF(D)]) = [type]" - var/formatted_type = replacetext("[type]", "/", "/") + else if(isimage(thing)) + var/image/image_object = thing + sprite = icon(image_object.icon, image_object.icon_state) var/sprite_text if(sprite) - sprite_text = no_icon? "\[NO ICON\]" : "" - var/list/header = islist(D)? list("/list") : D.vv_get_header() + hash = md5(sprite) + src << browse_rsc(sprite, "vv[hash].png") + sprite_text = no_icon ? "\[NO ICON\]" : "" + + title = "[thing] ([REF(thing)]) = [type]" + var/formatted_type = replacetext("[type]", "/", "/") + + var/list/header = islist ? list("/list") : thing.vv_get_header() var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay var/marked_line - if(holder && holder.marked_datum && holder.marked_datum == D) + if(holder && holder.marked_datum && holder.marked_datum == thing) marked_line = VV_MSG_MARKED var/tagged_line - if(holder && LAZYFIND(holder.tagged_datums, D)) - var/tag_index = LAZYFIND(holder.tagged_datums, D) + if(holder && LAZYFIND(holder.tagged_datums, thing)) + var/tag_index = LAZYFIND(holder.tagged_datums, thing) tagged_line = VV_MSG_TAGGED(tag_index) var/varedited_line - if(!islist && (D.datum_flags & DF_VAR_EDITED)) + if(!islist && (thing.datum_flags & DF_VAR_EDITED)) varedited_line = VV_MSG_EDITED var/deleted_line - if(!islist && D.gc_destroyed) + if(!islist && thing.gc_destroyed) deleted_line = VV_MSG_DELETED var/list/dropdownoptions @@ -75,28 +79,29 @@ var/link = dropdownoptions[name] dropdownoptions[i] = "" else - dropdownoptions = D.vv_get_dropdown() + dropdownoptions = thing.vv_get_dropdown() var/list/names = list() if(!islist) - for(var/V in D.vars) - names += V - sleep(1) + for(var/varname in thing.vars) + names += varname + + sleep(1 TICKS) var/list/variable_html = list() if(islist) - var/list/L = D - for(var/i in 1 to L.len) - var/key = L[i] + var/list/list_value = thing + for(var/i in 1 to list_value.len) + var/key = list_value[i] var/value - if(IS_NORMAL_LIST(L) && IS_VALID_ASSOC_KEY(key)) - value = L[key] - variable_html += debug_variable(i, value, 0, L) + if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key)) + value = list_value[key] + variable_html += debug_variable(i, value, 0, list_value) else names = sort_list(names) - for(var/V in names) - if(D.can_vv_get(V)) - variable_html += D.vv_get_var(V) + for(var/varname in names) + if(thing.can_vv_get(varname)) + variable_html += thing.vv_get_var(varname) var/html = {" @@ -274,5 +279,5 @@ datumrefresh=[refid];[HrefToken()]'>Refresh "} src << browse(html, "window=variables[refid];size=475x650") -/client/proc/vv_update_display(datum/D, span, content) - src << output("[span]:[content]", "variables[REF(D)].browser:replace_span") +/client/proc/vv_update_display(datum/thing, span, content) + src << output("[span]:[content]", "variables[REF(thing)].browser:replace_span")