Skip to content

Commit

Permalink
VV ports + fixes neon carpet (#810)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: LemonInTheDark <[email protected]>
  • Loading branch information
3 people authored Feb 12, 2024
1 parent e2fd017 commit c0d2b55
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 98 deletions.
5 changes: 5 additions & 0 deletions code/__DEFINES/_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
9 changes: 9 additions & 0 deletions code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/layers.dm
Original file line number Diff line number Diff line change
@@ -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

Expand Down
5 changes: 5 additions & 0 deletions code/__DEFINES/vv.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
6 changes: 6 additions & 0 deletions code/controllers/globals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions code/datums/elements/decals/_decal.dm
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
_layer,
_dir
)
pic.plane = _plane
pic.color = _color
pic.alpha = _alpha
return TRUE
Expand Down
4 changes: 2 additions & 2 deletions code/game/turfs/open/floor/fancy_floor.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
136 changes: 77 additions & 59 deletions code/modules/admin/view_variables/debug_variables.dm
Original file line number Diff line number Diff line change
@@ -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 = "<li style='backgroundColor:white'>([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]
. = "<li style='backgroundColor:white'>([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 = "<li style='backgroundColor:white'>([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)]) "
. = "<li style='backgroundColor:white'>([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 = "<li>"
. = "<li>"

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 = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'>[VV_HTML_ENCODE(name)] [REF(name)]</a>"
else if(islist(name))
var/list/L = name
name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(L)]) [REF(name)]</a>"
var/list/list_value = name
name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(list_value)]) [REF(name)]</a>"

if (isnull(value))
item = "[name_part] = <span class='value'>null</span>"
. = "[.][name_part] = "

else if (istext(value))
item = "[name_part] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
var/item = _debug_variable_value(name, value, level, owner, sanitize, display_flags)

else if (isicon(value))
return "[.][item]</li>"

// 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)
. = "<font color='red'>DISPLAY_ERROR</font>"

if(isnull(value))
return "<span class='value'>null</span>"

if(istext(value))
return "<span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"

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] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
var/rname = "tmp[REF(icon_value)][rnd].png"
usr << browse_rsc(icon_value, rname)
return "(<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
#else
item = "[name_part] = /icon (<span class='value'>[value]</span>)"
return "/icon (<span class='value'>[value]</span>)"
#endif

else if (isfile(value))
item = "[name_part] = <span class='value'>'[value]'</span>"
if(isappearance(value))
var/image/actually_an_appearance = value
return "/appearance (<br><span class='value'>icon: [actually_an_appearance.icon]<br>state: [actually_an_appearance.icon_state]<br>plane: [actually_an_appearance.plane]<br>layer: [actually_an_appearance.layer]</span>)"

else if(istype(value,/matrix)) // Needs to be before datum
var/matrix/M = value
item = {"[name_part] = <span class='value'>
<table class='matrixbrak'><tbody><tr><td class='lbrak'>&nbsp;</td><td>
<table class='matrix'>
<tbody>
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
</tbody>
</table></td><td class='rbrak'>&nbsp;</td></tr></tbody></table></span>"} //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] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[DV] [DV.type] [REF(value)]</a>"
else
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[DV.type] [REF(value)]</a>"
if(istype(value,/datum/weakref))
var/datum/weakref/weakref = value
item += " <a href='?_src_=vars;[HrefToken()];Vars=[REF(weakref.reference)]'>(Resolve)</a>"
if(isfilter(value))
var/datum/filter_value = value
return "/filter (<span class='value'>[filter_value.type] [REF(filter_value)]</span>)"

else if (islist(value))
var/list/L = value
if(isfile(value))
return "<span class='value'>'[value]'</span>"

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] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>/list ([L.len])</a><ul>[items.Join()]</ul>"
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(owner)];special_varname=[name]'>/list ([list_value.len])</a><ul>[items.Join()]</ul>"
else
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>/list ([L.len])</a>"
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(owner)];special_varname=[name]'>/list ([list_value.len])</a>"

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] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return "<span class='value'>[VV_HTML_ENCODE(value)]</span>"

/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 "<a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[src] [type] [REF(src)]</a>"
else
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[type] [REF(src)]</a>"

/datum/weakref/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
. = ..()
return "[.] <a href='?_src_=vars;[HrefToken()];Vars=[reference]'>(Resolve)</a>"

return "[header][item]</li>"
/matrix/debug_variable_value(name, level, datum/owner, sanitize, display_flags)
return {"<span class='value'>
<table class='matrixbrak'><tbody><tr><td class='lbrak'>&nbsp;</td><td>
<table class='matrix'>
<tbody>
<tr><td>[a]</td><td>[d]</td><td>0</td></tr>
<tr><td>[b]</td><td>[e]</td><td>0</td></tr>
<tr><td>[c]</td><td>[f]</td><td>1</td></tr>
</tbody>
</table></td><td class='rbrak'>&nbsp;</td></tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices

#undef VV_HTML_ENCODE
5 changes: 4 additions & 1 deletion code/modules/admin/view_variables/topic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading

0 comments on commit c0d2b55

Please sign in to comment.