mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-12 02:22:11 +00:00
This adds Message filters to Goonchat (only for mentors + administrators). There is a new option in the settings dropdown of Goonchat to access these. They are temporary, non-destructive filters which will hide all messages matching them that are already in your chat, as well as any new messages matching them. There are 5 filters currently: - Admin; Filters out most admin logs. - Combat; Filters out a limited subset of combat messages- Specifically, any message with the 'combat' span class. Currently, this has only been added to the central /attack and /attacked_by procs, so a large considerable amount of hostile actions taken against a player are still not going to be filtered out. We can work on adding the identifier to more stuff later. - Radios: Filters out all radio messages. - Speech: Filters out all mob speech. - OOC: Filters out OOC chat. There is also an "All" option, which just turns off all messages that are not internal to Goonchat.
279 lines
8.2 KiB
Plaintext
279 lines
8.2 KiB
Plaintext
var/list/chatResources = list(
|
|
"goon/browserassets/js/jquery.min.js",
|
|
"goon/browserassets/js/jquery.mark.min.js",
|
|
"goon/browserassets/js/json2.min.js",
|
|
"goon/browserassets/js/twemoji.min.js",
|
|
"goon/browserassets/js/browserOutput.js",
|
|
"goon/browserassets/css/fonts/fontawesome-webfont.eot",
|
|
"goon/browserassets/css/fonts/fontawesome-webfont.svg",
|
|
"goon/browserassets/css/fonts/fontawesome-webfont.ttf",
|
|
"goon/browserassets/css/fonts/fontawesome-webfont.woff",
|
|
"goon/browserassets/css/font-awesome.css",
|
|
"goon/browserassets/css/browserOutput.css",
|
|
"goon/browserassets/json/unicode_9_annotations.json"
|
|
)
|
|
|
|
/var/savefile/iconCache = new /savefile("data/iconCache.sav")
|
|
/var/chatDebug = file("data/chatDebug.log")
|
|
|
|
/datum/chatOutput
|
|
var/client/owner = null
|
|
var/loaded = 0
|
|
var/list/messageQueue = list()
|
|
var/cookieSent = 0
|
|
var/list/connectionHistory = list()
|
|
var/broken = FALSE
|
|
|
|
/datum/chatOutput/New(client/C)
|
|
. = ..()
|
|
|
|
owner = C
|
|
|
|
/datum/chatOutput/proc/start()
|
|
if(!owner)
|
|
return 0
|
|
|
|
if(!winexists(owner, "browseroutput"))
|
|
spawn()
|
|
alert(owner.mob, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.")
|
|
broken = TRUE
|
|
return 0
|
|
|
|
if(!owner) // In case the client vanishes before winexists returns
|
|
return 0
|
|
|
|
if(winget(owner, "browseroutput", "is-disabled") == "false")
|
|
doneLoading()
|
|
|
|
else
|
|
load()
|
|
|
|
return 1
|
|
|
|
/datum/chatOutput/proc/load()
|
|
set waitfor = FALSE
|
|
if(!owner)
|
|
return
|
|
|
|
for(var/attempts in 1 to 5)
|
|
for(var/asset in global.chatResources)
|
|
owner << browse_rsc(file(asset))
|
|
|
|
for(var/subattempts in 1 to 3)
|
|
owner << browse(file2text("goon/browserassets/html/browserOutput.html"), "window=browseroutput")
|
|
sleep(10 SECONDS)
|
|
if(!owner || loaded)
|
|
return
|
|
|
|
/datum/chatOutput/Topic(var/href, var/list/href_list)
|
|
if(usr.client != owner)
|
|
return 1
|
|
|
|
var/list/params = list()
|
|
for(var/key in href_list)
|
|
if(length(key) > 7 && findtext(key, "param"))
|
|
var/param_name = copytext(key, 7, -1)
|
|
var/item = href_list[key]
|
|
params[param_name] = item
|
|
|
|
var/data
|
|
switch(href_list["proc"])
|
|
if("doneLoading")
|
|
data = doneLoading(arglist(params))
|
|
|
|
if("debug")
|
|
data = debug(arglist(params))
|
|
|
|
if("ping")
|
|
data = ping(arglist(params))
|
|
|
|
if("analyzeClientData")
|
|
data = analyzeClientData(arglist(params))
|
|
|
|
if(data)
|
|
ehjax_send(data = data)
|
|
|
|
/datum/chatOutput/proc/doneLoading()
|
|
if(loaded)
|
|
return
|
|
|
|
loaded = TRUE
|
|
winset(owner, "browseroutput", "is-disabled=false")
|
|
if(owner.holder)
|
|
loadAdmin()
|
|
for(var/message in messageQueue)
|
|
to_chat(owner, message)
|
|
|
|
messageQueue = null
|
|
src.sendClientData()
|
|
|
|
pingLoop()
|
|
|
|
/datum/chatOutput/proc/pingLoop()
|
|
set waitfor = FALSE
|
|
|
|
while (owner)
|
|
ehjax_send(data = owner.is_afk(29 SECONDS) ? "softPang" : "pang") // SoftPang isn't handled anywhere but it'll always reset the opts.lastPang.
|
|
sleep(30 SECONDS)
|
|
|
|
/datum/chatOutput/proc/ehjax_send(var/client/C = owner, var/window = "browseroutput", var/data)
|
|
if(islist(data))
|
|
data = json_encode(data)
|
|
C << output("[data]", "[window]:ehjaxCallback")
|
|
|
|
/datum/chatOutput/proc/loadAdmin()
|
|
var/data = json_encode(list("loadAdminCode" = replacetext(replacetext(file2text("goon/browserassets/html/adminOutput.html"), "\n", ""), "\t", "")))
|
|
ehjax_send(data = url_encode(data))
|
|
|
|
/datum/chatOutput/proc/sendClientData()
|
|
var/list/deets = list("clientData" = list())
|
|
deets["clientData"]["ckey"] = owner.ckey
|
|
deets["clientData"]["ip"] = owner.address
|
|
deets["clientData"]["compid"] = owner.computer_id
|
|
var/data = json_encode(deets)
|
|
ehjax_send(data = data)
|
|
|
|
/datum/chatOutput/proc/analyzeClientData(cookie = "")
|
|
if(!cookie)
|
|
return
|
|
|
|
if(cookie != "none")
|
|
var/list/connData = json_decode(cookie)
|
|
if(connData && islist(connData) && connData.len > 0 && connData["connData"])
|
|
connectionHistory = connData["connData"]
|
|
var/list/found = new()
|
|
for(var/i = connectionHistory.len; i >= 1; i--)
|
|
var/list/row = connectionHistory[i]
|
|
if(!row || row.len < 3 || !(row["ckey"] && row["compid"] && row["ip"]))
|
|
return
|
|
if(world.IsBanned(row["ckey"], row["compid"], row["ip"]))
|
|
found = row
|
|
break
|
|
|
|
//Uh oh this fucker has a history of playing on a banned account!!
|
|
if (found.len > 0)
|
|
//TODO: add a new evasion ban for the CURRENT client details, using the matched row details
|
|
message_admins("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])")
|
|
log_admin("[key_name(src.owner)] has a cookie from a banned account! (Matched: [found["ckey"]], [found["ip"]], [found["compid"]])")
|
|
|
|
cookieSent = 1
|
|
|
|
/datum/chatOutput/proc/ping()
|
|
return "pong"
|
|
|
|
/datum/chatOutput/proc/debug(error)
|
|
error = "\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client : [owner.key ? owner.key : owner] triggered JS error: [error]"
|
|
chatDebug << error
|
|
|
|
/client/verb/debug_chat()
|
|
set hidden = 1
|
|
chatOutput.ehjax_send(data = list("firebug" = 1))
|
|
|
|
|
|
/var/list/bicon_cache = list()
|
|
|
|
//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
|
|
// exporting it as text, and then parsing the base64 from that.
|
|
// (This relies on byond automatically storing icons in savefiles as base64)
|
|
/proc/icon2base64(var/icon/icon, var/iconKey = "misc")
|
|
if (!isicon(icon)) return 0
|
|
|
|
iconCache[iconKey] << icon
|
|
var/iconData = iconCache.ExportText(iconKey)
|
|
var/list/partial = splittext(iconData, "{")
|
|
return replacetext(copytext(partial[2], 3, -5), "\n", "")
|
|
|
|
/proc/bicon(var/obj, var/use_class = 1)
|
|
var/class = use_class ? "class='icon misc'" : null
|
|
if (!obj)
|
|
return
|
|
|
|
if (isicon(obj))
|
|
if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it.
|
|
bicon_cache["\ref[obj]"] = icon2base64(obj)
|
|
|
|
return "<img [class] src='data:image/png;base64,[bicon_cache["\ref[obj]"]]'>"
|
|
|
|
// Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
|
|
var/atom/A = obj
|
|
var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
|
|
if (!bicon_cache[key]) // Doesn't exist, make it.
|
|
var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
|
|
if (ishuman(obj)) // Shitty workaround for a BYOND issue.
|
|
var/icon/temp = I
|
|
I = icon()
|
|
I.Insert(temp, dir = SOUTH)
|
|
bicon_cache[key] = icon2base64(I, key)
|
|
if(use_class)
|
|
class = "class='icon [A.icon_state]'"
|
|
|
|
return "<img [class] src='data:image/png;base64,[bicon_cache[key]]'>"
|
|
|
|
/proc/is_valid_tochat_message(message)
|
|
return istext(message)
|
|
|
|
/proc/is_valid_tochat_target(target)
|
|
return !istype(target, /savefile) && (ismob(target) || islist(target) || isclient(target) || target == world)
|
|
|
|
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)
|
|
if(!is_valid_tochat_message(message) || !is_valid_tochat_target(target))
|
|
target << message
|
|
|
|
// Info about the "message"
|
|
if(isnull(message))
|
|
message = "(null)"
|
|
else if(istype(message, /datum))
|
|
var/datum/D = message
|
|
message = "([D.type]): '[D]'"
|
|
else if(!is_valid_tochat_message(message))
|
|
message = "(bad message) : '[message]'"
|
|
|
|
// Info about the target
|
|
var/targetstring = "'[target]'"
|
|
if(istype(target, /datum))
|
|
var/datum/D = target
|
|
targetstring += ", [D.type]"
|
|
|
|
// The final output
|
|
log_runtime(new/exception("DEBUG: to_chat called with invalid message/target.", to_chat_filename, to_chat_line), to_chat_src, list("Message: '[message]'", "Target: [targetstring]"))
|
|
return
|
|
|
|
else if(is_valid_tochat_message(message))
|
|
if(istext(target))
|
|
log_runtime(EXCEPTION("Somehow, to_chat got a text as a target"))
|
|
return
|
|
|
|
message = replacetext(message, "\n", "<br>")
|
|
|
|
message = macro2html(message)
|
|
if(findtext(message, "\improper"))
|
|
message = replacetext(message, "\improper", "")
|
|
if(findtext(message, "\proper"))
|
|
message = replacetext(message, "\proper", "")
|
|
|
|
var/client/C
|
|
if(istype(target, /client))
|
|
C = target
|
|
if(ismob(target))
|
|
C = target:client
|
|
|
|
if(C && C.chatOutput)
|
|
if(C.chatOutput.broken)
|
|
C << message
|
|
return
|
|
|
|
if(!C.chatOutput.loaded && C.chatOutput.messageQueue && islist(C.chatOutput.messageQueue))
|
|
C.chatOutput.messageQueue.Add(message)
|
|
return
|
|
|
|
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the javascript.
|
|
var/output_message = "[url_encode(url_encode(message))]"
|
|
if(flag)
|
|
output_message += "&[url_encode(flag)]"
|
|
|
|
target << output(output_message, "browseroutput:output")
|