From 347a52eb52d9bb9b2f692212fc99069fc5d33636 Mon Sep 17 00:00:00 2001
From: tralezab <40974010+tralezab@users.noreply.github.com>
Date: Wed, 24 Jul 2019 21:23:05 -0700
Subject: [PATCH] Chat Subsystem ported from TerraGov-Marine-Corps (#45354)
* chat subsystem v0.1
* removes old tabulator
* updates the check on to_chat
* SSchat now initializes
---
code/__DEFINES/subsystems.dm | 10 ++--
code/controllers/subsystem/chat.dm | 68 ++++++++++++++++++++++++++
code/modules/goonchat/browserOutput.dm | 10 +++-
tgstation.dme | 1 +
4 files changed, 83 insertions(+), 6 deletions(-)
create mode 100644 code/controllers/subsystem/chat.dm
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 6727c64b570..e05e0d20c99 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -1,12 +1,12 @@
//! Defines for subsystems and overlays
-//!
+//!
//! Lots of important stuff in here, make sure you have your brain switched on
//! when editing this file
//! ## DB defines
/**
* DB major schema version
- *
+ *
* Update this whenever the db schema changes
*
* make sure you add an update to the schema_version stable in the db changelog
@@ -15,7 +15,7 @@
/**
* DB minor schema version
- *
+ *
* Update this whenever the db schema changes
*
* make sure you add an update to the schema_version stable in the db changelog
@@ -132,7 +132,8 @@
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
#define INIT_ORDER_DISCORD -60
-#define INIT_ORDER_PERSISTENCE -100
+#define INIT_ORDER_PERSISTENCE -95
+#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
@@ -161,6 +162,7 @@
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
#define FIRE_PRIORITY_ATMOS_ADJACENCY 300
+#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
new file mode 100644
index 00000000000..a103a0eaafe
--- /dev/null
+++ b/code/controllers/subsystem/chat.dm
@@ -0,0 +1,68 @@
+SUBSYSTEM_DEF(chat)
+ name = "Chat"
+ flags = SS_TICKER|SS_NO_INIT
+ wait = 1
+ priority = FIRE_PRIORITY_CHAT
+ init_order = INIT_ORDER_CHAT
+
+ var/list/payload = list()
+
+
+/datum/controller/subsystem/chat/fire()
+ for(var/i in payload)
+ var/client/C = i
+ C << output(payload[C], "browseroutput:output")
+ payload -= C
+
+ if(MC_TICK_CHECK)
+ return
+
+
+/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE)
+ if(!target || !message)
+ return
+
+ if(!istext(message))
+ stack_trace("to_chat called with invalid input type")
+ return
+
+ if(target == world)
+ target = GLOB.clients
+
+ //Some macros remain in the string even after parsing and fuck up the eventual output
+ message = replacetext(message, "\improper", "")
+ message = replacetext(message, "\proper", "")
+ if(handle_whitespace)
+ message = replacetext(message, "\n", "
")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
+ message += "
"
+
+
+ //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
+ //Do the double-encoding here to save nanoseconds
+ var/twiceEncoded = url_encode(url_encode(message))
+
+ if(islist(target))
+ for(var/I in target)
+ var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ continue
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ continue
+
+ payload[C] += twiceEncoded
+
+ else
+ var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ return
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ return
+
+ payload[C] += twiceEncoded
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 2a4b37cd2b3..f3b0fbffc2f 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -205,8 +205,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]")
//Global chat procs
-/proc/to_chat(target, message, handle_whitespace=TRUE)
- if(!target)
+/proc/to_chat_immediate(target, message, handle_whitespace = TRUE)
+ if(!target || !message)
return
if(target == world)
@@ -258,6 +258,12 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
C << output(url_encode(url_encode(message)), "browseroutput:output")
+/proc/to_chat(target, message, handle_whitespace = TRUE)
+ if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized)
+ to_chat_immediate(target, message, handle_whitespace)
+ return
+ SSchat.queue(target, message, handle_whitespace)
+
/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation)
owner.force_white_theme()
diff --git a/tgstation.dme b/tgstation.dme
index 4dd91d01001..e747e1e4d4b 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -230,6 +230,7 @@
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\augury.dm"
#include "code\controllers\subsystem\blackbox.dm"
+#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
#include "code\controllers\subsystem\dcs.dm"