Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TG Mirror] VV Upgrades [MDB IGNORE] #52

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions code/__DEFINES/_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@
/// : because of the embedded typecheck
#define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]"))
#endif

// 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)
8 changes: 7 additions & 1 deletion code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@

#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) (!istype(thing, /image) && !ispath(thing) && istype(GLOB.magic_appearance_detecting_image, thing))
#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))

Expand Down
135 changes: 74 additions & 61 deletions code/modules/admin/view_variables/debug_variables.dm
Original file line number Diff line number Diff line change
@@ -1,107 +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, display_flags = NONE) //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(isappearance(value))
if(isappearance(value))
var/image/actually_an_appearance = value
item = "[name_part] = /appearance (<span class='value'>[actually_an_appearance.icon]</span>)"
return "/appearance (<span class='value'>[actually_an_appearance.icon]</span>)"

else if (isfile(value))
item = "[name_part] = <span class='value'>'[value]'</span>"
if(isfilter(value))
var/datum/filter_value = value
return "/filter (<span class='value'>[filter_value.type] [REF(filter_value)]</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
if(isfile(value))
return "<span class='value'>'[value]'</span>"

else if (isdatum(value))
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=[weakref.reference]'>(Resolve)</a>"
if(isdatum(value))
var/datum/datum_value = value
return datum_value.debug_variable_value(name, level, owner, sanitize, display_flags)

else if (islist(value))
var/list/L = value
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 (!(display_flags & VV_ALWAYS_CONTRACT_LIST) && 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
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
item = "[name_part] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>[type] [REF(src)]</a>"

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

/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
75 changes: 40 additions & 35 deletions code/modules/admin/view_variables/view_variables.dm
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]", "/", "<wbr>/")
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\]" : "<img src='vv[hash].png'></td><td>"
var/list/header = islist(D)? list("<b>/list</b>") : D.vv_get_header()
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
sprite_text = no_icon ? "\[NO ICON\]" : "<img src='vv[hash].png'></td><td>"

title = "[thing] ([REF(thing)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")

var/list/header = islist ? list("<b>/list</b>") : 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
Expand All @@ -75,28 +79,29 @@
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
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
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 = {"
<html>
Expand Down Expand Up @@ -274,5 +279,5 @@ datumrefresh=[refid];[HrefToken()]'>Refresh</a>
"}
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")
Loading