mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-16 12:43:09 +00:00
About The Pull Request Adds extools-powered reference tracking. Includes a couple procs that retrieve the back and forward references of a datum - Back references let you see what is referencing your object and potentially preventing it from garbage collecting, and forward ones show you what your object in turn references. Also made a cool GUI to inspect and follow these references. The tracking adds some overhead to all variable sets and list operations. Init time is increased by ~15%. I haven't actually benched it so it might impact the actual game less. Why It's Good For The Game no lagging caused by hard dels scanning the entire planet (once coders fix them)
269 lines
7.5 KiB
Plaintext
269 lines
7.5 KiB
Plaintext
/client/proc/debug_variables(datum/D in world)
|
|
set category = "Debug"
|
|
set name = "View Variables"
|
|
//set src in world
|
|
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
|
|
|
|
if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs.
|
|
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>", confidential = TRUE)
|
|
return
|
|
|
|
if(!D)
|
|
return
|
|
|
|
var/islist = islist(D)
|
|
if(!islist && !istype(D))
|
|
return
|
|
|
|
var/title = ""
|
|
var/refid = REF(D)
|
|
var/icon/sprite
|
|
var/hash
|
|
|
|
var/type = islist? /list : D.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
|
|
no_icon = TRUE
|
|
|
|
title = "[D] ([REF(D)]) = [type]"
|
|
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
|
|
|
|
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()
|
|
|
|
var/marked_line
|
|
if(holder && holder.marked_datum && holder.marked_datum == D)
|
|
marked_line = VV_MSG_MARKED
|
|
var/varedited_line
|
|
if(!islist && (D.datum_flags & DF_VAR_EDITED))
|
|
varedited_line = VV_MSG_EDITED
|
|
var/deleted_line
|
|
if(!islist && D.gc_destroyed)
|
|
deleted_line = VV_MSG_DELETED
|
|
|
|
var/list/dropdownoptions
|
|
if (islist)
|
|
dropdownoptions = list(
|
|
"---",
|
|
"Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD),
|
|
"Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS),
|
|
"Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES),
|
|
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
|
|
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
|
|
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
|
|
"View References" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_VIEW_REFERENCES),
|
|
"---"
|
|
)
|
|
for(var/i in 1 to length(dropdownoptions))
|
|
var/name = dropdownoptions[i]
|
|
var/link = dropdownoptions[name]
|
|
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
|
|
else
|
|
dropdownoptions = D.vv_get_dropdown()
|
|
|
|
var/list/names = list()
|
|
if(!islist)
|
|
for(var/V in D.vars)
|
|
names += V
|
|
sleep(1)
|
|
|
|
var/list/variable_html = list()
|
|
if(islist)
|
|
var/list/L = D
|
|
for(var/i in 1 to L.len)
|
|
var/key = L[i]
|
|
var/value
|
|
if(IS_NORMAL_LIST(L) && IS_VALID_ASSOC_KEY(key))
|
|
value = L[key]
|
|
variable_html += debug_variable(i, value, 0, L)
|
|
else
|
|
names = sortList(names)
|
|
for(var/V in names)
|
|
if(D.can_vv_get(V))
|
|
variable_html += D.vv_get_var(V)
|
|
|
|
var/html = {"
|
|
<html>
|
|
<head>
|
|
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
|
<title>[title]</title>
|
|
<link rel="stylesheet" type="text/css" href="view_variables.css">
|
|
</head>
|
|
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
|
|
<script type="text/javascript">
|
|
// onload
|
|
function selectTextField() {
|
|
var filter_text = document.getElementById('filter');
|
|
filter_text.focus();
|
|
filter_text.select();
|
|
var lastsearch = getCookie("[refid][cookieoffset]search");
|
|
if (lastsearch) {
|
|
filter_text.value = lastsearch;
|
|
updateSearch();
|
|
}
|
|
}
|
|
function getCookie(cname) {
|
|
var name = cname + "=";
|
|
var ca = document.cookie.split(';');
|
|
for(var i=0; i<ca.length; i++) {
|
|
var c = ca\[i];
|
|
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
|
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
// main search functionality
|
|
var last_filter = "";
|
|
function updateSearch() {
|
|
var filter = document.getElementById('filter').value.toLowerCase();
|
|
var vars_ol = document.getElementById("vars");
|
|
|
|
if (filter === last_filter) {
|
|
// An event triggered an update but nothing has changed.
|
|
return;
|
|
} else if (filter.indexOf(last_filter) === 0) {
|
|
// The new filter starts with the old filter, fast path by removing only.
|
|
var children = vars_ol.childNodes;
|
|
for (var i = children.length - 1; i >= 0; --i) {
|
|
try {
|
|
var li = children\[i];
|
|
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
|
|
vars_ol.removeChild(li);
|
|
}
|
|
} catch(err) {}
|
|
}
|
|
} else {
|
|
// Remove everything and put back what matches.
|
|
while (vars_ol.hasChildNodes()) {
|
|
vars_ol.removeChild(vars_ol.lastChild);
|
|
}
|
|
|
|
for (var i = 0; i < complete_list.length; ++i) {
|
|
try {
|
|
var li = complete_list\[i];
|
|
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
|
|
vars_ol.appendChild(li);
|
|
}
|
|
} catch(err) {}
|
|
}
|
|
}
|
|
|
|
last_filter = filter;
|
|
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
|
|
|
|
}
|
|
|
|
// onkeydown
|
|
function handle_keydown() {
|
|
if(event.keyCode == 116) { //F5 (to refresh properly)
|
|
document.getElementById("refresh_link").click();
|
|
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// onkeyup
|
|
function handle_keyup() {
|
|
updateSearch();
|
|
}
|
|
|
|
// onchange
|
|
function handle_dropdown(list) {
|
|
var value = list.options\[list.selectedIndex].value;
|
|
if (value !== "") {
|
|
location.href = value;
|
|
}
|
|
list.selectedIndex = 0;
|
|
document.getElementById('filter').focus();
|
|
}
|
|
|
|
// byjax
|
|
function replace_span(what) {
|
|
var idx = what.indexOf(':');
|
|
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
|
|
}
|
|
</script>
|
|
<div align='center'>
|
|
<table width='100%'>
|
|
<tr>
|
|
<td width='50%'>
|
|
<table align='center' width='100%'>
|
|
<tr>
|
|
<td>
|
|
[sprite_text]
|
|
<div align='center'>
|
|
[header.Join()]
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<div align='center'>
|
|
<b><font size='1'>[formatted_type]</font></b>
|
|
<span id='marked'>[marked_line]</span>
|
|
<span id='varedited'>[varedited_line]</span>
|
|
<span id='deleted'>[deleted_line]</span>
|
|
</div>
|
|
</td>
|
|
<td width='50%'>
|
|
<div align='center'>
|
|
<a id='refresh_link' href='?_src_=vars;
|
|
datumrefresh=[refid];[HrefToken()]'>Refresh</a>
|
|
<form>
|
|
<select name="file" size="1"
|
|
onchange="handle_dropdown(this)"
|
|
onmouseclick="this.focus()">
|
|
<option value selected>Select option</option>
|
|
[dropdownoptions.Join()]
|
|
</select>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<hr>
|
|
<font size='1'>
|
|
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
|
|
<b>C</b> - Change, asks you for the var type first.<br>
|
|
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
|
|
</font>
|
|
<hr>
|
|
<table width='100%'>
|
|
<tr>
|
|
<td width='20%'>
|
|
<div align='center'>
|
|
<b>Search:</b>
|
|
</div>
|
|
</td>
|
|
<td width='80%'>
|
|
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<hr>
|
|
<ol id='vars'>
|
|
[variable_html.Join()]
|
|
</ol>
|
|
<script type='text/javascript'>
|
|
var complete_list = \[\];
|
|
var lis = document.getElementById("vars").children;
|
|
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
|
|
</script>
|
|
</body>
|
|
</html>
|
|
"}
|
|
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")
|