diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index b491bc6e354..3377bb59009 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -265,6 +265,8 @@ #define TRIGGER_GUARD_NONE 0 #define TRIGGER_GUARD_NORMAL 1 +#define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) + // Macro to get the current elapsed round time, rather than total world runtime #define ROUND_TIME (SSticker.round_start_time ? (world.time - SSticker.round_start_time) : 0) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 29a93ae94f9..c55fec2cd87 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -79,7 +79,8 @@ #define INIT_ORDER_NANOMOB -23 #define INIT_ORDER_SQUEAK -40 #define INIT_ORDER_PATH -50 -#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) @@ -111,6 +112,7 @@ #define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_NANOUI 110 #define FIRE_PRIORITY_TICKER 200 +#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..a90e14d0ab4 --- /dev/null +++ b/code/controllers/subsystem/chat.dm @@ -0,0 +1,65 @@ +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, flag) + 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", "") + 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 \ No newline at end of file diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index 3456e0a2ce9..3359e7c6232 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -222,7 +222,7 @@ var/to_chat_filename var/to_chat_line var/to_chat_src // Call using macro: to_chat(target, message, flag) -/proc/__to_chat(target, message, flag) +/proc/to_chat_immediate(target, message, flag) if(!is_valid_tochat_message(message) || !is_valid_tochat_target(target)) target << message @@ -279,3 +279,9 @@ var/to_chat_src output_message += "&[url_encode(flag)]" target << output(output_message, "browseroutput:output") + +/proc/__to_chat(target, message, flag) + if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized) + to_chat_immediate(target, message, flag) + return + SSchat.queue(target, message, flag) diff --git a/paradise.dme b/paradise.dme index 270d843845c..a72e37f3219 100644 --- a/paradise.dme +++ b/paradise.dme @@ -203,6 +203,7 @@ #include "code\controllers\subsystem\alarm.dm" #include "code\controllers\subsystem\assets.dm" #include "code\controllers\subsystem\atoms.dm" +#include "code\controllers\subsystem\chat.dm" #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\fires.dm" #include "code\controllers\subsystem\garbage.dm"