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

VV editor can now see /appearance types #10885

Merged
merged 22 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
1 change: 1 addition & 0 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,7 @@
#include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.dm"
#include "code\modules\admin\view_variables\admin_delete.dm"
#include "code\modules\admin\view_variables\color_matrix_editor.dm"
#include "code\modules\admin\view_variables\debug_variable_appearance.dm"
#include "code\modules\admin\view_variables\debug_variables.dm"
#include "code\modules\admin\view_variables\filterrific.dm"
#include "code\modules\admin\view_variables\get_variables.dm"
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#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) (!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")))
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/vv.dm
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@

//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(src)]'>[name]</option>"
//Same with VV_DROPDOWN_OPTION, but global proc doesn't have src
#define VV_DROPDOWN_OPTION_APPEARANCE(thing, href_key, name) . += "<option value='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(thing)]'>[name]</option>"

// VV HREF KEYS
#define VV_HK_TARGET "target"
Expand Down
197 changes: 197 additions & 0 deletions code/modules/admin/view_variables/debug_variable_appearance.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/* < OH MY GOD. Can't you just make "/image/proc/foo()" instead of making these? >
* /appearance is a hardcoded byond type, and it is very internal type.
* Its type is actually /image, but it isn't truly /image. We defined it as "/appearance"
* new procs to /image will only work to actual /image references, but...
* /appearance references are not capable of executing procs, because these are not real /image
PowerfulBacon marked this conversation as resolved.
Show resolved Hide resolved
* This is why these global procs exist. Welcome to the curse.
*/
/// Makes a var list of /appearance type actually uses. This will be only called once.
/proc/build_virtual_appearance_vars()
. = list("vis_flags") // manual listing
var/list/unused_var_names = list(
"appearance", // it only does self-reference
"x","y","z", // these are always 0
"weak_reference", // it's not a good idea to make a weak_ref on this, and this won't have it
"vars", // inherited from /image, but /appearance hasn't this

// we have no reason to show those, right?
"active_timers",
"comp_lookup",
"datum_components",
"signal_procs",
"status_traits",
"gc_destroyed",
"stat_tabs",
"cooldowns",
"datum_flags",
"visibility",
"verbs",
"tgui_shared_states"
)
var/image/dummy_image = image(null, null)
for(var/each in dummy_image.vars) // try to inherit var list from /image
if(each in unused_var_names)
continue
. += each
del(dummy_image)
dummy_image = null

/// appearance type needs a manual var referencing because it doesn't have "vars" variable internally.
/// There's no way doing this in a fancier way.
/proc/debug_variable_appearance(var_name, image/appearance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the thing coming in isn't an image, then it shouldn't be typed as an image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Welcome to Byond

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least it's a single case. I converted it to movable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats even worse, its definitely not an atom/movable. Its a variable type and should be untyped, with the type being resolved later on.

Copy link
Member

@PowerfulBacon PowerfulBacon Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why even bother typing it with the wrong type, just use the unsafe access operator, :, and keep it untyped

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aight changed

var/atom/movable/atom_appearance = appearance
var/value
try
switch(var_name) // Welcome to this curse
// appearance doesn't have "vars" variable.
// This means you need to target a variable manually through this way.

// appearance vars in DM document
if("alpha")
value = appearance.alpha
if("appearance_flags")
value = appearance.appearance_flags
if("blend_mode")
value = appearance.blend_mode
if("color")
value = appearance.color
if("desc")
value = appearance.desc
if("gender")
value = appearance.gender
if("icon")
value = appearance.icon
if("icon_state")
value = appearance.icon_state
if("invisibility")
value = appearance.invisibility
if("infra_luminosity")
value = atom_appearance.infra_luminosity
if("filters")
value = appearance.filters
if("layer")
value = appearance.layer
if("luminosity")
value = appearance.luminosity
if("maptext")
value = appearance.maptext
if("maptext_width")
value = appearance.maptext_width
if("maptext_height")
value = appearance.maptext_height
if("maptext_x")
value = appearance.maptext_x
if("maptext_y")
value = appearance.maptext_y
if("mouse_over_pointer")
value = appearance.mouse_over_pointer
if("mouse_drag_pointer")
value = appearance.mouse_drag_pointer
if("mouse_drop_pointer")
value = appearance.mouse_drop_pointer
if("mouse_drop_zone")
value = appearance.mouse_drop_zone
if("mouse_opacity")
value = appearance.mouse_opacity
if("name")
value = appearance.name
if("opacity")
value = appearance.opacity
if("overlays")
value = appearance.overlays
if("override")
value = appearance.override
if("pixel_x")
value = appearance.pixel_x
if("pixel_y")
value = appearance.pixel_y
if("pixel_w")
value = appearance.pixel_w
if("pixel_z")
value = appearance.pixel_z
if("plane")
value = appearance.plane
if("render_source")
value = appearance.render_source
if("render_target")
value = appearance.render_target
if("suffix")
value = appearance.suffix
if("text")
value = appearance.text
if("transform")
value = appearance.transform
if("underlays")
value = appearance.underlays

if("parent_type")
value = appearance.parent_type
if("type")
value = "/appearance (as [appearance.type])" // don't fool people

// These are not documented ones but trackable values. Maybe we'd want these.
if("animate_movement")
value = atom_appearance.animate_movement
if("dir")
value = atom_appearance.dir
if("glide_size")
value = atom_appearance.glide_size
if("pixel_step_size")
value = "" //atom_appearance.pixel_step_size
// DM compiler complains this

// I am not sure if these will be ever detected, but I made a connection just in case.
if("contents")
value = atom_appearance.contents
if("vis_contents")
value = atom_appearance.vis_contents
if("vis_flags") // DM document says /appearance has this, but it throws error
value = atom_appearance.vis_flags
if("loc")
value = atom_appearance.loc

// we wouldn't need these, but let's these trackable anyway...
if("density")
value = atom_appearance.density
if("screen_loc")
value = atom_appearance.screen_loc
if("sorted_verbs")
value = atom_appearance.sorted_verbs
if("tag")
value = atom_appearance.tag
if("cached_ref")
value = appearance.cached_ref

else
return "<li style='backgroundColor:white'>(READ ONLY) [var_name] <font color='blue'>(Undefined var name in switch)</font></li>"
catch
return "<li style='backgroundColor:white'>(READ ONLY) <font color='blue'>[var_name] = (untrackable)</font></li>"
return "<li style='backgroundColor:white'>(READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, appearance, sanitize = TRUE, display_flags = NONE)]</li>"

/// Shows a header name on top when you investigate an appearance
/proc/vv_get_header_appearance(image/thing)
. = list()
var/icon_name = "<b>[thing.icon || "null"]</b><br/>"
. += replacetext(icon_name, "icons/obj", "") // shortens the name. We know the path already.
if(thing.icon)
. += thing.icon_state ? "\"[thing.icon_state]\"" : "(icon_state = null)"

/image/vv_get_header() // it should redirect to global proc version because /appearance can't call a proc, unless we want dupe code here
return vv_get_header_appearance(src)

/// Makes a format name for shortened vv name.
/proc/get_appearance_vv_summary_name(image/thing)
var/icon_file_name = thing.icon ? splittext("[thing.icon]", "/") : "null"
if(islist(icon_file_name))
icon_file_name = length(icon_file_name) ? icon_file_name[length(icon_file_name)] : "null"
if(thing.icon_state)
return "[icon_file_name]:[thing.icon_state]"
else
return "[icon_file_name]"

/proc/vv_get_dropdown_appearance(image/thing)
. = list()
// unless you have a good reason to add a vv option for /appearance,
// /appearance type shouldn't alloow any vv option. Even "Mark Datum" is a questionable behaviour here.
VV_DROPDOWN_OPTION_APPEARANCE(thing, "", "---")
VV_DROPDOWN_OPTION_APPEARANCE(thing, "", "VV option not allowed")
9 changes: 6 additions & 3 deletions code/modules/admin/view_variables/debug_variables.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@
return "/icon (<span class='value'>[value]</span>)"
#endif

if(isappearance(value))
var/image/actually_an_appearance = value
return "/appearance (<span class='value'>[actually_an_appearance.icon]</span>)"
if(isappearance(value)) // Reminder: Do not replace this into /image/debug_variable_value() proc. /appearance can't do that.
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>/appearance (<span class='value'>[get_appearance_vv_summary_name(value)]</span>) [REF(value)]</a>"

if(isimage(value))
var/image/image = value
return "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[image.type] (<span class='value'>[get_appearance_vv_summary_name(image)]</span>) [REF(value)]</a>"

if(isfilter(value))
var/datum/filter_value = value
Expand Down
27 changes: 21 additions & 6 deletions code/modules/admin/view_variables/view_variables.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,30 @@
var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv)
asset_cache_datum.send(usr)

var/isappearance = isappearance(thing)
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))
if(!islist && !isdatum(thing) && !isappearance)
return

var/title = ""
var/refid = REF(thing)
var/icon/sprite
var/hash

var/type = islist? /list : thing.type
var/type = islist? /list : (isappearance ? "/appearance" : thing.type)
var/no_icon = FALSE

if(isatom(thing))
sprite = getFlatIcon(thing)
if(!sprite)
no_icon = TRUE

else if(isimage(thing))
else if(isimage(thing) || isappearance(thing))
var/image/image_object = thing
sprite = icon(image_object.icon, image_object.icon_state)
// icon_state=null shows first image even if dmi has no icon_state for null name.
// Unless dmi has a single icon_state as null name, let's skip null-name because it's confusing
if(image_object.icon_state || length(icon_states(image_object.icon)) == 1)
sprite = icon(image_object.icon, image_object.icon_state)

var/sprite_text
if(sprite)
Expand All @@ -44,7 +48,7 @@
title = "[thing] ([REF(thing)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")

var/list/header = islist ? list("<b>/list</b>") : thing.vv_get_header()
var/list/header = islist ? list("<b>/list</b>") : (isappearance ? vv_get_header_appearance(thing) : thing.vv_get_header())

var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay

Expand Down Expand Up @@ -78,11 +82,18 @@
var/name = dropdownoptions[i]
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
else if(isappearance)
dropdownoptions = vv_get_dropdown_appearance(thing)
else
dropdownoptions = thing.vv_get_dropdown()

var/list/names = list()
if(!islist)
if(isappearance)
var/static/list/virtual_appearance_vars
if(!virtual_appearance_vars)
virtual_appearance_vars = build_virtual_appearance_vars()
names = virtual_appearance_vars.Copy()
else if(!islist)
for(var/varname in thing.vars)
names += varname

Expand All @@ -97,6 +108,10 @@
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 if(isappearance)
names = sort_list(names)
for(var/varname in names)
variable_html += debug_variable_appearance(varname, thing)
else
names = sort_list(names)
for(var/varname in names)
Expand Down
Loading