TGUI Fix verb, TGUI AI state fix, TGUI focus fix

This commit is contained in:
ShadowLarkens
2020-09-16 19:54:54 -07:00
parent 44f65e2602
commit ef846b5807
4 changed files with 75 additions and 17 deletions

View File

@@ -12,9 +12,10 @@
*
* required user mob The mob who opened/is using the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional parent_ui datum/tgui A parent UI that, when closed, closes this UI as well.
*/
/datum/proc/tgui_interact(mob/user, datum/tgui/ui = null)
/datum/proc/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui/parent_ui = null)
return FALSE // Not implemented.
/**
@@ -27,7 +28,7 @@
*
* return list Data to be sent to the UI.
*/
/datum/proc/tgui_data(mob/user)
/datum/proc/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
return list() // Not implemented.
/**
@@ -140,6 +141,26 @@
*/
/datum/proc/tgui_close(mob/user)
/**
* verb
*
* Used by a client to fix broken TGUI windows caused by opening a UI window before assets load.
* Probably not very performant and forcibly destroys a bunch of windows, so it has some warnings attached.
* Conveniently, also allows devs to force a dev server reattach without relogging, since it yeets windows.
*/
/client/verb/tgui_fix_white()
set desc = "Only use this if you have a broken TGUI window occupying your screen!"
set name = "Fix TGUI"
set category = "OOC"
if(alert(src, "Only use this verb if you have a white TGUI window stuck on your screen.", "Fix TGUI", "Continue", "Nevermind") != "Continue")
return
SStgui.close_user_uis(mob)
if(alert(src, "Did that fix the problem?", "Fix TGUI", "Yes", "No") == "No")
SStgui.force_close_all_windows(mob)
alert(src, "UIs should be fixed now. If not, please cry to your nearest coder.", "Fix TGUI")
/**
* verb
*

View File

@@ -36,13 +36,29 @@ GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
return STATUS_DISABLED // Otherwise they can keep the UI open.
/mob/living/silicon/ai/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. < STATUS_INTERACTIVE)
. = shared_tgui_interaction()
if(. != STATUS_INTERACTIVE)
return
// The AI can interact with anything it can see nearby, or with cameras while wireless control is enabled.
if(!control_disabled && can_see(src_object))
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in using_map.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return STATUS_CLOSE
return STATUS_INTERACTIVE
else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/simple_animal/default_can_use_tgui_topic(src_object)

View File

@@ -34,8 +34,12 @@
var/status = STATUS_INTERACTIVE
/// Topic state used to determine status/interactability.
var/datum/tgui_state/state = null
// The map z-level to display.
/// The map z-level to display.
var/map_z_level = 1
/// The Parent UI
var/datum/tgui/parent_ui
/// Children of this UI
var/list/children = list()
/**
* public
@@ -46,12 +50,13 @@
* required src_object datum The object or datum which owns the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
* optional parent_ui datum/tgui The parent of this UI.
* optional ui_x int Deprecated: Window width.
* optional ui_y int Deprecated: Window height.
*
* return datum/tgui The requested UI.
*/
/datum/tgui/New(mob/user, datum/src_object, interface, title, ui_x, ui_y)
/datum/tgui/New(mob/user, datum/src_object, interface, title, datum/tgui/parent_ui, ui_x, ui_y)
src.user = user
src.src_object = src_object
src.window_key = "[REF(src_object)]-main"
@@ -59,6 +64,9 @@
if(title)
src.title = title
src.state = src_object.tgui_state()
src.parent_ui = parent_ui
if(parent_ui)
parent_ui.children += src
// Deprecated
if(ui_x && ui_y)
src.window_size = list(ui_x, ui_y)
@@ -100,10 +108,13 @@
*
* Close the UI, and all its children.
*/
/datum/tgui/proc/close(can_be_suspended = TRUE)
/datum/tgui/proc/close(can_be_suspended = TRUE, logout = FALSE)
if(closing)
return
closing = TRUE
for(var/datum/tgui/child in children)
child.close(can_be_suspended, logout)
children.Cut()
// If we don't have window_id, open proc did not have the opportunity
// to finish, therefore it's safe to skip this whole block.
if(window)
@@ -111,10 +122,11 @@
// and we want to keep them around, to allow user to read
// the error message properly.
window.release_lock()
window.close(can_be_suspended)
window.close(can_be_suspended, logout)
src_object.tgui_close(user)
SStgui.on_close(src)
state = null
parent_ui = null
qdel(src)
/**
@@ -209,7 +221,7 @@
"observer" = isobserver(user),
),
)
var/data = custom_data || with_data && src_object.tgui_data(user)
var/data = custom_data || with_data && src_object.tgui_data(user, src, state)
if(data)
json_data["data"] = data
var/static_data = with_static_data && src_object.tgui_static_data(user)
@@ -244,7 +256,7 @@
return
// Update through a normal call to ui_interact
if(status != STATUS_DISABLED && (autoupdate || force))
src_object.tgui_interact(user, src)
src_object.tgui_interact(user, src, parent_ui)
return
// Update status only
var/needs_update = process_status()
@@ -262,6 +274,8 @@
/datum/tgui/proc/process_status()
var/prev_status = status
status = src_object.tgui_status(user, state)
if(parent_ui)
status = min(status, parent_ui.status)
return prev_status != status
/datum/tgui/proc/log_message(message)

View File

@@ -133,13 +133,19 @@
*
* optional can_be_suspended bool
*/
/datum/tgui_window/proc/close(can_be_suspended = TRUE)
/datum/tgui_window/proc/close(can_be_suspended = TRUE, logout = FALSE)
if(!client)
return
if(can_be_suspended && can_be_suspended())
log_tgui(client, "[id]/close: suspending")
status = TGUI_WINDOW_READY
send_message("suspend")
// You would think that BYOND would null out client or make it stop passing istypes or, y'know, ANYTHING during
// logout, but nope! It appears to be perfectly valid to call winset by every means we can measure in Logout,
// and yet it causes a bad client runtime. To avoid that happening, we just have to know if we're in Logout or
// not.
if(!logout && client)
winset(client, null, "mapwindow.map.focus=true")
return
log_tgui(client, "[id]/close")
release_lock()
@@ -149,7 +155,8 @@
// to read the error message.
if(!fatally_errored)
client << browse(null, "window=[id]")
if(!logout && client)
winset(client, null, "mapwindow.map.focus=true")
/**
* public
*
@@ -189,9 +196,9 @@
/datum/tgui_window/proc/send_asset(datum/asset/asset)
if(!client || !asset)
return
// if(istype(asset, /datum/asset/spritesheet))
// var/datum/asset/spritesheet/spritesheet = asset
// send_message("asset/stylesheet", spritesheet.css_filename())
if(istype(asset, /datum/asset/spritesheet))
var/datum/asset/spritesheet/spritesheet = asset
send_message("asset/stylesheet", spritesheet.css_filename())
send_message("asset/mappings", asset.get_url_mappings())
sent_assets += list(asset)
asset.send(client)