Makes alt-click more responsive and fixes its item handling (#31366)

* make alt click inspect responsive and fix a bug

* switch to list operation wow
This commit is contained in:
Pooble
2026-01-23 06:26:57 -08:00
committed by GitHub
parent d153830534
commit 6744a3a66f
2 changed files with 120 additions and 29 deletions
+58 -3
View File
@@ -112,7 +112,7 @@ SUBSYSTEM_DEF(statpanels)
for(var/image/target_image as anything in target.images)
if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override)
continue
overrides += target_image.loc
overrides[target_image.loc] = TRUE
var/list/atoms_to_display = list(target_mob.listed_turf)
for(var/atom/movable/turf_content as anything in target_mob.listed_turf)
@@ -120,7 +120,7 @@ SUBSYSTEM_DEF(statpanels)
continue
if(turf_content.invisibility > target_mob.see_invisible)
continue
if(turf_content in overrides)
if(overrides[turf_content])
continue
if(turf_content.IsObscured())
continue
@@ -129,6 +129,8 @@ SUBSYSTEM_DEF(statpanels)
/// Set the atoms we're meant to display
var/datum/object_window_info/obj_window = istype(target.obj_window) ? target.obj_window : new(target)
obj_window.atoms_to_show = atoms_to_display
// don't generate icons for stuff the user will not see
obj_window.atoms_to_imagify &= atoms_to_display
refresh_client_obj_view(target, obj_window.min_index, obj_window.max_index)
/datum/controller/subsystem/statpanels/proc/refresh_client_obj_view(client/refresh, min_index = 0, max_index = 30)
@@ -160,6 +162,8 @@ SUBSYSTEM_DEF(statpanels)
var/list/turf_items = list()
var/i = 0
var/client_uid = load_from.UID()
// While an item's icon is being generated, we send no image URL and let the frontend render an empty slot.
var/static/no_image_url = ""
for(var/atom/turf_item as anything in obj_window.atoms_to_show)
// Limit what we send to the client's rendered section.
i++
@@ -169,7 +173,11 @@ SUBSYSTEM_DEF(statpanels)
// First, we fill up the list of refs to display
// If we already have one, just use that
var/existing_image = already_seen[turf_item]
// rows that are still loading are still sent, we just won't send an image, frontend will hotswap it in
if(existing_image == OBJ_IMAGE_LOADING)
var/obj_m5_uid_loading = turf_item.MD5_UID()
load_from.m5_uid_cache[obj_m5_uid_loading] = turf_item.unique_datum_id
turf_items["[i]"] = list("[turf_item.name]", obj_m5_uid_loading, no_image_url, "", client_uid)
continue
// We already have it. Success!
@@ -254,6 +262,10 @@ SUBSYSTEM_DEF(statpanels)
var/client/parent
/// Are we currently tracking a turf?
var/actively_tracking = FALSE
/// Turf we are currently listening to for content changes.
var/turf/tracked_turf
/// Debounce flag for immediate refreshes.
var/pending_turf_refresh = FALSE
/// The minimum index currently sent to the client.
var/min_index = 0
/// The maximum index currently sent to the client.
@@ -264,6 +276,9 @@ SUBSYSTEM_DEF(statpanels)
src.parent = parent
/datum/object_window_info/Destroy(force, ...)
if(tracked_turf)
UnregisterSignal(tracked_turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED, COMSIG_TURF_CHANGE))
tracked_turf = null
atoms_to_show = null
atoms_to_images = null
atoms_to_imagify = null
@@ -303,6 +318,13 @@ SUBSYSTEM_DEF(statpanels)
/datum/object_window_info/proc/start_turf_tracking()
if(actively_tracking)
stop_turf_tracking()
var/turf/new_tracked = parent?.mob?.listed_turf
if(new_tracked)
// We're setting up signals here so updates are instant rather than laggy and slow.
tracked_turf = new_tracked
RegisterSignal(tracked_turf, COMSIG_ATOM_ENTERED, PROC_REF(on_tracked_turf_entered))
RegisterSignal(tracked_turf, COMSIG_ATOM_EXITED, PROC_REF(on_tracked_turf_exited))
RegisterSignal(tracked_turf, COMSIG_TURF_CHANGE, PROC_REF(on_tracked_turf_change))
var/static/list/connections = list(
COMSIG_MOVABLE_MOVED = PROC_REF(on_mob_move),
COMSIG_MOB_LOGOUT = PROC_REF(on_mob_logout),
@@ -312,8 +334,38 @@ SUBSYSTEM_DEF(statpanels)
/datum/object_window_info/proc/stop_turf_tracking()
DeleteComponent(/datum/component/connect_mob_behalf)
if(tracked_turf)
UnregisterSignal(tracked_turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED, COMSIG_TURF_CHANGE))
tracked_turf = null
pending_turf_refresh = FALSE
actively_tracking = FALSE
/datum/object_window_info/proc/queue_listedturf_refresh()
if(pending_turf_refresh)
return
pending_turf_refresh = TRUE
// This accumulates all of our updates and does one refresh rather than calling a dozen refreshes when a dozen things change
addtimer(CALLBACK(src, PROC_REF(do_listedturf_refresh)), 1)
/datum/object_window_info/proc/do_listedturf_refresh()
pending_turf_refresh = FALSE
if(!parent?.mob?.listed_turf)
return
// If the user moved away, let the existing adjacency logic close the tab.
SSstatpanels.set_turf_examine_tab(parent, parent.mob)
/datum/object_window_info/proc/on_tracked_turf_entered(atom/source, atom/movable/entered, atom/old_loc)
SIGNAL_HANDLER // COMSIG_ATOM_ENTERED
queue_listedturf_refresh()
/datum/object_window_info/proc/on_tracked_turf_exited(atom/source, atom/movable/exiting, direction)
SIGNAL_HANDLER // COMSIG_ATOM_EXITED
queue_listedturf_refresh()
/datum/object_window_info/proc/on_tracked_turf_change(atom/source)
SIGNAL_HANDLER // COMSIG_TURF_CHANGE
queue_listedturf_refresh()
/datum/object_window_info/proc/on_mob_move(mob/source)
SIGNAL_HANDLER
var/turf/listed = source.listed_turf
@@ -330,7 +382,7 @@ SUBSYSTEM_DEF(statpanels)
SIGNAL_HANDLER
atoms_to_show -= deleted
atoms_to_imagify -= deleted
atoms_to_images -= deleted
atoms_to_images[deleted] = null
/mob/proc/set_listed_turf(turf/new_turf)
listed_turf = new_turf
@@ -347,3 +399,6 @@ SUBSYSTEM_DEF(statpanels)
else
client.stat_panel.send_message("remove_listedturf")
client.obj_window.stop_turf_tracking()
// Don't generate icons when the tab's closed.
client.obj_window.atoms_to_show.Cut()
client.obj_window.atoms_to_imagify.Cut()
+62 -26
View File
@@ -381,7 +381,12 @@ function listedturf_add_row(table, table_index, true_index) {
turf_incomplete_rows[true_index] = true_index + 1;
}
function listedturf_fill_row(row, item_index) {
function listedturf_render_row(row, item_index) {
// Clear any previous contents so we don't mess up list indices
while (row.firstChild) {
row.removeChild(row.firstChild);
}
let object_info = turfcontents['' + item_index];
if (!object_info) {
return false;
@@ -428,32 +433,46 @@ function listedturf_fill_row(row, item_index) {
cell.appendChild(button);
let img = document.createElement('img');
img.id = object_info[1];
img.src = object_info[2];
img.style.verticalAlign = 'middle';
img.style.width = turf_row_inner_height + 'em';
img.style.height = turf_row_inner_height + 'em';
img.onerror = (function (object_info) {
return function () {
let delay = imageRetryDelay;
if (!turf_image_errors[object_info[3]]) {
turf_image_errors[object_info[3]] = 0;
delay = imageFirstRetryDelay;
}
turf_image_errors[object_info[3]]++;
if (turf_image_errors[object_info[3]] > imageRetryLimit) {
return;
}
if (object_info[2]) {
img.id = object_info[1];
img.src = object_info[2];
img.style.verticalAlign = 'middle';
img.style.width = turf_row_inner_height + 'em';
img.style.height = turf_row_inner_height + 'em';
// Only retry if we got an asset key
if (object_info[3]) {
img.onerror = (function (object_info) {
return function () {
let delay = imageRetryDelay;
if (!turf_image_errors[object_info[3]]) {
turf_image_errors[object_info[3]] = 0;
delay = imageFirstRetryDelay;
}
turf_image_errors[object_info[3]]++;
if (turf_image_errors[object_info[3]] > imageRetryLimit) {
return;
}
Byond.sendMessage('Resend-Asset', object_info[3]);
setTimeout(function () {
// Use the failure count as a cachebreaker to force-reload.
let img = document.getElementById(object_info[1]);
img.src = object_info[2] + '?' + turf_image_errors[object_info[3]];
}, imageRetryDelay);
};
})(object_info);
button.appendChild(img);
Byond.sendMessage('Resend-Asset', object_info[3]);
setTimeout(function () {
// Use the failure count as a cachebreaker to force-reload.
let img = document.getElementById(object_info[1]);
if (img) {
img.src = object_info[2] + '?' + turf_image_errors[object_info[3]];
}
}, delay);
};
})(object_info);
}
button.appendChild(img);
} else {
// If we're missing an image URL just space out the same amount that the image would take up
let spacer = document.createElement('span');
spacer.style.display = 'inline-block';
spacer.style.width = turf_row_inner_height + 'em';
spacer.style.height = turf_row_inner_height + 'em';
button.appendChild(spacer);
}
var label = document.createElement('span');
label.style.marginLeft = '0.5em';
@@ -463,6 +482,22 @@ function listedturf_fill_row(row, item_index) {
return true;
}
function listedturf_fill_row(row, item_index) {
return listedturf_render_row(row, item_index);
}
function listedturf_refresh_visible_rows() {
if (!turf_rows || !turf_rows.initialized) {
return;
}
for (let i = turf_rows.min_row; i < turf_rows.max_row; i++) {
if (turf_rows[i]) {
listedturf_render_row(turf_rows[i], i + 1);
delete turf_incomplete_rows[i];
}
}
}
function listedturf_fill_all() {
for (let i in turf_incomplete_rows) {
let item_index = turf_incomplete_rows[i];
@@ -915,6 +950,7 @@ Byond.subscribeTo('update_listedturf', function (TC) {
turf_size = TC['total'];
if (current_tab == turfname) {
draw_listedturf();
listedturf_refresh_visible_rows();
}
});