actual tgui code

This commit is contained in:
Letter N
2020-08-17 21:07:09 +08:00
parent 610e25beb7
commit 55bd3ecc26
9 changed files with 507 additions and 50 deletions
+42
View File
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/// Admin music volume, from 0 to 1.
/client/var/admin_music_volume = 1
/**
* public
*
* Sends music data to the browser.
*
* Optional settings:
* - pitch: the playback rate
* - start: the start time of the sound
* - end: when the musics stops playing
*
* required url string Must be an https URL.
* optional extra_data list Optional settings.
*/
/datum/tgui_panel/proc/play_music(url, extra_data)
if(!is_ready())
return
if(!findtext(url, GLOB.is_http_protocol))
return
var/list/payload = list()
if(length(extra_data) > 0)
for(var/key in extra_data)
payload[key] = extra_data[key]
payload["url"] = url
window.send_message("audio/playMusic", payload)
/**
* public
*
* Stops playing music through the browser.
*/
/datum/tgui_panel/proc/stop_music()
if(!is_ready())
return
window.send_message("audio/stopMusic")
+53
View File
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/client/var/datum/tgui_panel/tgui_panel
/**
* tgui panel / chat troubleshooting verb
*/
/client/verb/fix_chat()
set name = "Fix chat"
set category = "OOC"
var/action
log_tgui(src, "tgui_panel: Started fix_chat.")
// Not initialized
if(!tgui_panel || !istype(tgui_panel))
log_tgui(src, "tgui_panel: datum is missing")
action = alert(src, "tgui panel was not initialized!\nSet it up again?", "", "OK", "Cancel")
if(action != "OK")
return
tgui_panel = new(src)
tgui_panel.initialize()
action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope")
if(action == "Fixed")
log_tgui(src, "tgui_panel: Fixed by calling 'new' + 'initialize'")
return
// Not ready
if(!tgui_panel?.is_ready())
log_tgui(src, "tgui_panel: not ready")
action = alert(src, "tgui panel looks like it's waiting for something.\nSend it a ping?", "", "OK", "Cancel")
if(action != "OK")
return
tgui_panel.window.send_message("ping", force = TRUE)
action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope")
if(action == "Fixed")
log_tgui(src, "tgui_panel: Fixed by sending a ping")
return
// Catch all solution
action = alert(src, "Looks like tgui panel was already setup, but we can always try again.\nSet it up again?", "", "OK", "Cancel")
if(action != "OK")
return
tgui_panel.initialize(force = TRUE)
action = alert(src, "Wait a bit and tell me if it's fixed", "", "Fixed", "Nope")
if(action == "Fixed")
log_tgui(src, "tgui_panel: Fixed by calling 'initialize'")
return
// Failed to fix
action = alert(src, "Welp, I'm all out of ideas. Try closing BYOND and reconnecting.\nWe could also disable tgui_panel and re-enable the old UI", "", "Thanks anyways", "Switch to old UI")
if (action == "Switch to old UI")
winset(src, "output", "on-show=&is-disabled=0&is-visible=1")
winset(src, "browseroutput", "is-disabled=1;is-visible=0")
log_tgui(src, "tgui_panel: Failed to fix.")
+80
View File
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* Maximum number of connection records allowed to analyze.
* Should match the value set in the browser.
*/
#define TGUI_TELEMETRY_MAX_CONNECTIONS 5
/**
* Maximum time allocated for sending a telemetry packet.
*/
#define TGUI_TELEMETRY_RESPONSE_WINDOW 30 SECONDS
/// Time of telemetry request
/datum/tgui_panel/var/telemetry_requested_at
/// Time of telemetry analysis completion
/datum/tgui_panel/var/telemetry_analyzed_at
/// List of previous client connections
/datum/tgui_panel/var/list/telemetry_connections
/**
* private
*
* Requests some telemetry from the client.
*/
/datum/tgui_panel/proc/request_telemetry()
telemetry_requested_at = world.time
telemetry_analyzed_at = null
window.send_message("telemetry/request", list(
"limits" = list(
"connections" = TGUI_TELEMETRY_MAX_CONNECTIONS,
),
))
/**
* private
*
* Analyzes a telemetry packet.
*
* Is currently only useful for detecting ban evasion attempts.
*/
/datum/tgui_panel/proc/analyze_telemetry(payload)
if(world.time > telemetry_requested_at + TGUI_TELEMETRY_RESPONSE_WINDOW)
message_admins("[key_name(client)] sent telemetry outside of the allocated time window.")
return
if(telemetry_analyzed_at)
message_admins("[key_name(client)] sent telemetry more than once.")
return
telemetry_analyzed_at = world.time
if(!payload)
return
telemetry_connections = payload["connections"]
var/len = length(telemetry_connections)
if(len == 0)
return
if(len > TGUI_TELEMETRY_MAX_CONNECTIONS)
message_admins("[key_name(client)] was kicked for sending a huge telemetry payload")
qdel(client)
return
var/list/found
for(var/i in 1 to len)
if(QDELETED(client))
// He got cleaned up before we were done
return
var/list/row = telemetry_connections[i]
// Check for a malformed history object
if (!row || row.len < 3 || (!row["ckey"] || !row["address"] || !row["computer_id"]))
return
if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE))
found = row
break
CHECK_TICK
// This fucker has a history of playing on a banned account.
if(found)
var/msg = "[key_name(client)] has a banned account in connection history! (Matched: [found["ckey"]], [found["address"]], [found["computer_id"]])"
message_admins(msg)
log_admin_private(msg)
+95
View File
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* tgui_panel datum
* Hosts tgchat and other nice features.
*/
/datum/tgui_panel
var/client/client
var/datum/tgui_window/window
var/broken = FALSE
var/initialized_at
/datum/tgui_panel/New(client/client)
src.client = client
window = new(client, "browseroutput")
window.subscribe(src, .proc/on_message)
/datum/tgui_panel/Del()
window.unsubscribe(src)
window.close()
return ..()
/**
* public
*
* TRUE if panel is initialized and ready to receive messages.
*/
/datum/tgui_panel/proc/is_ready()
return !broken && window.is_ready()
/**
* public
*
* Initializes tgui panel.
*/
/datum/tgui_panel/proc/initialize(force = FALSE)
initialized_at = world.time
// Perform a clean initialization
window.initialize(inline_assets = list(
get_asset_datum(/datum/asset/simple/tgui_common),
get_asset_datum(/datum/asset/simple/tgui_panel),
))
window.send_asset(get_asset_datum(/datum/asset/simple/namespaced/fontawesome))
window.send_asset(get_asset_datum(/datum/asset/spritesheet/chat))
request_telemetry()
addtimer(CALLBACK(src, .proc/on_initialize_timed_out), 2 SECONDS)
/**
* private
*
* Called when initialization has timed out.
*/
/datum/tgui_panel/proc/on_initialize_timed_out()
// Currently does nothing but sending a message to old chat.
SEND_TEXT(client, "<span class=\"userdanger\">Failed to load fancy chat, reverting to old chat. Certain features won't work.</span>")
/**
* private
*
* Callback for handling incoming tgui messages.
*/
/datum/tgui_panel/proc/on_message(type, payload)
if(type == "ready")
broken = FALSE
window.send_message("update", list(
"config" = list(
"client" = list(
"ckey" = client.ckey,
"address" = client.address,
"computer_id" = client.computer_id,
),
"window" = list(
"fancy" = FALSE,
"locked" = FALSE,
),
),
))
return TRUE
if(type == "audio/setAdminMusicVolume")
client.admin_music_volume = payload["volume"]
return TRUE
if(type == "telemetry")
analyze_telemetry(payload)
return TRUE
/**
* public
*
* Sends a round restart notification.
*/
/datum/tgui_panel/proc/send_roundrestart()
window.send_message("roundrestart")
+71
View File
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* global
*
* Circumvents the message queue and sends the message
* to the recipient (target) as soon as possible.
*/
/proc/to_chat_immediate(
target,
text,
handle_whitespace = TRUE,
trailing_newline = TRUE,
confidential = FALSE)
if(!target || !text)
return
if(target == world)
target = GLOB.clients
var/flags = handle_whitespace \
| trailing_newline << 1 \
| confidential << 2
var/message = TGUI_CREATE_MESSAGE("chat/message", list(
"text" = text,
"flags" = flags,
))
if(islist(target))
for(var/_target in target)
var/client/client = CLIENT_FROM_VAR(_target)
if(client)
// Send to tgchat
client.tgui_panel?.window.send_raw_message(message)
// Send to old chat
SEND_TEXT(client, text)
return
var/client/client = CLIENT_FROM_VAR(target)
if(client)
// Send to tgchat
client.tgui_panel?.window.send_raw_message(message)
// Send to old chat
SEND_TEXT(client, text)
/**
* global
*
* Sends the message to the recipient (target).
*/
/proc/to_chat(
target,
text,
handle_whitespace = TRUE,
trailing_newline = TRUE,
confidential = FALSE)
if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized)
to_chat_immediate(
target,
text,
handle_whitespace,
trailing_newline,
confidential)
return
if(!target || !text)
return
if(target == world)
target = GLOB.clients
var/flags = handle_whitespace \
| trailing_newline << 1 \
| confidential << 2
SSchat.queue(target, text, flags)