From dafd19c708b1637b2b5797bda15f7430dcaa2d97 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Wed, 4 Mar 2020 20:53:35 -0500 Subject: [PATCH] Some VChat Tweaks - Chat remains between client reconnects if your client didn't close (so things like using the reconnect button, or autoreconnects at round end when that feels like working) - The client doesn't send pings to the server, the server sends pings to the client. This fixes AFK measurements for AFK kick purposes. - Turn latency indicator into a green/red indicator to show if you're connected, and when clicked will perform a one-time ping (and block doing it again for 10 seconds). It will display '?ms' if it never got a reply, or '999ms' if it did, but it was over 1s. --- code/modules/client/client procs.dm | 1 + code/modules/vchat/html/vchat.html | 19 +++--- code/modules/vchat/js/vchat.js | 94 ++++++++++++++++++++--------- code/modules/vchat/vchat_client.dm | 39 +++++++++--- interface/skin.dmf | 2 +- 5 files changed, 109 insertions(+), 46 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index cb8b70519e..f8ab8ec8e9 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -428,6 +428,7 @@ client/verb/character_setup() //Log, disable log_debug("[key_name(src)] reloaded VChat.") + winset(src, null, "outputwindow.htmloutput.is-visible=false;outputwindow.oldoutput.is-visible=false;outputwindow.chatloadlabel.is-visible=true") //The hard way qdel_null(src.chatOutput) diff --git a/code/modules/vchat/html/vchat.html b/code/modules/vchat/html/vchat.html index 6426defa57..a3612d78e4 100644 --- a/code/modules/vchat/html/vchat.html +++ b/code/modules/vchat/html/vchat.html @@ -18,8 +18,8 @@
-

VChat is still loading. If you see this for a very long time, try the OOC 'Reload VChat' verb, or reconnecting.

-

Sometimes if you're still caching resources, it will take longer than usual.

+

You probably shouldn't see this page. This generally means chat is very broken.

+

You can wait a few seconds to see if it loads, or try OOC > Reload VChat.

@@ -78,7 +84,6 @@

Global Settings

-

Clicking anywhere in VChat saves your settings.

@@ -116,19 +121,19 @@
- +
- +
- +
diff --git a/code/modules/vchat/js/vchat.js b/code/modules/vchat/js/vchat.js index 905505bcb8..bf1d2a16a4 100644 --- a/code/modules/vchat/js/vchat.js +++ b/code/modules/vchat/js/vchat.js @@ -24,8 +24,7 @@ //Options for vchat var vchat_opts = { - pingThisOften: 10000, //ms - pingDropsAllowed: 2, + msBeforeDropped: 30000, //No ping for this long, and the server must be gone cookiePrefix: "vst-", //If you're another server, you can change this if you want. alwaysShow: ["vc_looc", "vc_system"] //Categories to always display on every tab }; @@ -75,11 +74,8 @@ var vchat_state = { byond_ckey: null, //Ping status - lastPingAttempt: 0, - lastPingReply: 0, - missedPings: 0, - latency: 0, - reconnecting: false, + lastPingReceived: 0, + latency_sent: 0, //Last ID lastId: 0 @@ -99,8 +95,7 @@ function start_vchat() { doWinset("chatloadlabel", {"is-visible": false}); //Commence the pingening - send_ping(); - setInterval(send_ping, vchat_opts.pingThisOften); + setInterval(check_ping, vchat_opts.msBeforeDropped); //For fun send_debug("VChat Loaded!"); @@ -125,6 +120,7 @@ function start_vue() { editing: false, //If we're in settings edit mode paused: false, //Autoscrolling latency: 0, //Not necessarily network latency, since the game server has to align the responses into ticks + reconnecting: false, //If we've lost our connection ext_styles: "", //Styles for chat downloaded files is_admin: false, @@ -261,6 +257,13 @@ function start_vue() { } }, watch: { + reconnecting: function(newSetting, oldSetting) { + if(newSetting == true && oldSetting == false) { + this.internal_message("Your client has lost connection to the server, or there is severe lag. Your client will reconnect if possible."); + } else if (newSetting == false && oldSetting == true) { + this.internal_message("Your client has reconnected to the server."); + } + }, //Save the inverted setting to LS inverted: function (newSetting) { set_storage("darkmode",newSetting); @@ -335,11 +338,15 @@ function start_vue() { }, //What color does the latency pip get? ping_classes: function() { - if(this.latency === 0) { return "grey"; } + if(!this.latency) { + return this.reconnecting ? "red" : "green"; //Standard + } + + if (this.latency == "?") { return "grey"; } //Waiting for latency test reply else if(this.latency < 0 ) {return "red"; } else if(this.latency <= 200) { return "green"; } else if(this.latency <= 400) { return "yellow"; } - else { return "red"; } + else { return "grey"; } }, current_categories: function() { if(this.active_tab == this.tabs[0]) { @@ -603,6 +610,12 @@ function start_vue() { let blob = new Blob([textToSave], {type: 'text/html;charset=utf8;'}); saved = window.navigator.msSaveBlob(blob, filename); } + }, + do_latency_test: function() { + send_latency_check(); + }, + blur_this: function(event) { + event.target.blur(); } } }); @@ -613,21 +626,37 @@ function start_vue() { * Actual Methods * ************/ -//Send a 'ping' to byond and check to see if we got the last one back in a timely manner -function send_ping() { - vchat_state.latency = (Math.min(Math.max(vchat_state.lastPingReply - vchat_state.lastPingAttempt, -1), 999)); - //If their last reply was in the previous ping window or earlier. - if(vchat_state.latency < 0) { - vchat_state.missedPings++; - if((vchat_state.missedPings >= vchat_opts.pingDropsAllowed) && !vchat_state.reconnecting) { - system_message("Your client has lost connection with the server. It will reconnect automatically if possible."); - vchat_state.reconnecting = true; +function check_ping() { + var time_ago = Date.now() - vchat_state.lastPingReceived; + if(time_ago > vchat_opts.msBeforeDropped) + vueapp.reconnecting = true; +} + +//Send a 'ping' to byond +function send_latency_check() { + if(vchat_state.latency_sent) + return; + + vchat_state.latency_sent = Date.now(); + vueapp.latency = "?"; + push_Topic("ping"); + setTimeout(function() { + if(vchat_state.latency_ms == "?") { + vchat_state.latency_ms = 999; } + }, 1000); // 1 second to reply otherwise we mark it as bad + setTimeout(function() { + vchat_state.latency_sent = 0; + vueapp.latency = 0; + }, 5000); //5 seconds to display ping time overall +} + +function get_latency_check() { + if(!vchat_state.latency_sent) { + return; //Too late } - vueapp.latency = vchat_state.latency; - push_Topic("keepalive_client"); - vchat_state.lastPingAttempt = Date.now(); + vueapp.latency = Date.now() - vchat_state.latency_sent; } //We accept double-url-encoded JSON strings because Byond is garbage and UTF-8 encoded url_encode() text has crazy garbage in it. @@ -678,7 +707,7 @@ function send_debug(message) { //A side-channel to send events over that aren't just chat messages, if necessary. function get_event(event) { if(!vchat_state.ready) { - push_Topic('not_ready'); + push_Topic("not_ready"); return; } @@ -704,10 +733,19 @@ function get_event(event) { break; //Just a ping. - case 'keepalive_server': - vchat_state.lastPingReply = Date.now(); - vchat_state.missedPings = 0; - reconnecting = false; + case 'keepalive': + vchat_state.lastPingReceived = Date.now(); + vueapp.reconnecting = false; + break; + + //Response to a latency test. + case 'pong': + get_latency_check(); + break; + + //The server doesn't know if we're loaded or not (we bail above if we're not, so we must be). + case 'availability': + push_Topic("done_loading"); break; default: diff --git a/code/modules/vchat/vchat_client.dm b/code/modules/vchat/vchat_client.dm index ec32c08118..23900f2d3c 100644 --- a/code/modules/vchat/vchat_client.dm +++ b/code/modules/vchat/vchat_client.dm @@ -46,7 +46,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic . = ..() owner = C - update_vis() /datum/chatOutput/Destroy() owner = null @@ -78,14 +77,20 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic become_broken() return FALSE + //Could be loaded from a previous round, are you still there? + if(winget(owner,"outputwindow.htmloutput","is-visible") == "true") //Winget returns strings + send_event(event = list("evttype" = "availability")) + sleep(3 SECONDS) + if(!owner) // In case the client vanishes before winexists returns qdel(src) return FALSE - if(!resources_sent) - send_resources() - - load() + if(!loaded) + update_vis() + if(!resources_sent) + send_resources() + load() return TRUE @@ -115,7 +120,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic owner.chatOutputLoadedAt = world.time //update_vis() //It does it's own winsets - + ping_cycle() send_playerinfo() load_database() @@ -163,9 +168,23 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic /datum/chatOutput/proc/send_event(var/event, var/client/C = owner) C << output(jsEncode(event), "htmloutput:get_event") +//Looping sleeping proc that just pings the client and dies when we die +/datum/chatOutput/proc/ping_cycle() + set waitfor = FALSE + while(!QDELING(src)) + if(!owner) + qdel(src) + return + send_event(event = keep_alive()) + sleep(20 SECONDS) //Make sure this makes sense with what the js client is expecting + //Just produces a message for using in keepalives from the server to the client -/datum/chatOutput/proc/keepalive() - return list("evttype" = "keepalive_server") +/datum/chatOutput/proc/keep_alive() + return list("evttype" = "keepalive") + +//A response to a latency check from the client +/datum/chatOutput/proc/latency_check() + return list("evttype" = "pong") //Redirected from client/Topic when the user clicks a link that pertains directly to the chat (when src == "chat") /datum/chatOutput/Topic(var/href, var/list/href_list) @@ -197,8 +216,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic CRASH("Tried to send a message to [owner.ckey] chatOutput before it was ready!") if("done_loading") data = done_loading(arglist(params)) - if("keepalive_client") - data = keepalive(arglist(params)) + if("ping") + data = latency_check(arglist(params)) if("ident") data = bancheck(arglist(params)) if("unloading") diff --git a/interface/skin.dmf b/interface/skin.dmf index 865853f15c..917ff0455e 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1226,7 +1226,7 @@ window "outputwindow" background-color = #222222 is-visible = true saved-params = "" - text = "Chat is loading.\nIf nothing happens after 60s,\nuse OOC > \"Reload VChat\"." + text = "Chat is loading.\nIf nothing happens after 20s,\nuse OOC > \"Reload VChat\"." elem "htmloutput" type = BROWSER pos = 0,0