// SETUP /proc/TopicHandlers() . = list() var/list/all_handlers = subtypesof(/datum/world_topic) for(var/I in all_handlers) var/datum/world_topic/WT = I var/keyword = initial(WT.keyword) if(!keyword) warning("[WT] has no keyword! Ignoring...") continue var/existing_path = .[keyword] if(existing_path) warning("[existing_path] and [WT] have the same keyword! Ignoring [WT]...") else if(keyword == "key") warning("[WT] has keyword 'key'! Ignoring...") else .[keyword] = WT // DATUM /datum/world_topic var/keyword var/log = TRUE var/key_valid var/require_comms_key = FALSE /datum/world_topic/proc/TryRun(list/input) key_valid = config && config_legacy.comms_key == input["key"] && (config_legacy.comms_key != initial(config_legacy.comms_key)) //no fucking defaults allowed. //key_valid = config && (CONFIG_GET(string/comms_key) == input["key"]) if(require_comms_key && !key_valid) return "Bad Key" input -= "key" . = Run(input) if(islist(.)) . = list2params(.) /datum/world_topic/proc/Run(list/input) CRASH("Run() not implemented for [type]!") // TOPICS /datum/world_topic/ping keyword = "ping" log = FALSE /datum/world_topic/ping/Run(list/input) . = 0 for (var/client/C in GLOB.clients) ++. /datum/world_topic/playing keyword = "playing" log = FALSE /datum/world_topic/playing/Run(list/input) return length(player_list) /datum/world_topic/pr_announce keyword = "announce" require_comms_key = TRUE var/static/list/PRcounts = list() //PR id -> number of times announced this round /datum/world_topic/pr_announce/Run(list/input) var/list/payload = json_decode(input["payload"]) var/id = "[payload["pull_request"]["id"]]" if(!PRcounts[id]) PRcounts[id] = 1 else ++PRcounts[id] if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) return var/final_composed = "PR: [input[keyword]]" for(var/client/C in GLOB.clients) C.AnnouncePR(final_composed) /datum/world_topic/auto_bunker_passthrough keyword = "auto_bunker_override" require_comms_key = TRUE /datum/world_topic/auto_bunker_passthrough/Run(list/input) if(!CONFIG_GET(flag/allow_cross_server_bunker_override)) return "Function Disabled" var/ckeytobypass = input["ckey"] var/is_new_ckey = !(ckey(ckeytobypass) in GLOB.bunker_passthrough) var/sender = input["source"] || "UNKNOWN" GLOB.bunker_passthrough |= ckey(ckeytobypass) GLOB.bunker_passthrough[ckey(ckeytobypass)] = world.realtime SSpersistence.SavePanicBunker() //we can do this every time, it's okay if(!is_new_ckey) log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).") message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).") send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).") return "Success" /* /datum/world_topic/ahelp_relay keyword = "Ahelp" require_comms_key = TRUE /datum/world_topic/ahelp_relay/Run(list/input) relay_msg_admins("HELP: [input["source"]] [input["message_sender"]]: [input["message"]]") /datum/world_topic/comms_console keyword = "Comms_Console" require_comms_key = TRUE /datum/world_topic/comms_console/Run(list/input) minor_announce(input["message"], "Incoming message from [input["message_sender"]]") for(var/obj/machinery/computer/communications/CM in GLOB.machines) CM.overrideCooldown() /datum/world_topic/news_report keyword = "News_Report" require_comms_key = TRUE /datum/world_topic/news_report/Run(list/input) minor_announce(input["message"], "Breaking Update From [input["message_sender"]]") /datum/world_topic/server_hop keyword = "server_hop" /datum/world_topic/server_hop/Run(list/input) var/expected_key = input[keyword] for(var/mob/dead/observer/O in GLOB.player_list) if(O.key == expected_key) if(O.client) new /atom/movable/screen/splash(O.client, TRUE) break /datum/world_topic/adminmsg keyword = "adminmsg" require_comms_key = TRUE /datum/world_topic/adminmsg/Run(list/input) return IrcPm(input[keyword], input["msg"], input["sender"]) /datum/world_topic/namecheck keyword = "namecheck" require_comms_key = TRUE /datum/world_topic/namecheck/Run(list/input) //Oh this is a hack, someone refactor the functionality out of the chat command PLS var/datum/tgs_chat_command/namecheck/NC = new var/datum/tgs_chat_user/user = new user.friendly_name = input["sender"] user.mention = user.friendly_name return NC.Run(user, input["namecheck"]) /datum/world_topic/adminwho keyword = "adminwho" require_comms_key = TRUE /datum/world_topic/adminwho/Run(list/input) return ircadminwho() */ /datum/world_topic/jsonstatus keyword = "jsonstatus" /datum/world_topic/jsonstatus/Run(list/input, addr) . = list() .["mode"] = master_mode // .["round_id"] = null // GLOB.round_id .["players"] = GLOB.clients.len var/list/adm = get_admin_counts() var/list/presentmins = adm["present"] var/list/afkmins = adm["afk"] .["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho .["security_level"] = get_security_level() .["round_duration"] = roundduration2text() .["map"] = SSmapping.config.map_name return json_encode(.) /datum/world_topic/jsonplayers keyword = "jsonplayers" /datum/world_topic/jsonplayers/Run(list/input, addr) . = list() for(var/client/C in GLOB.clients) if(C.holder?.fakekey) . += C.holder.fakekey continue . += C.key return json_encode(.) /datum/world_topic/jsonmanifest keyword = "jsonmanifest" /datum/world_topic/jsonmanifest/Run(list/input, addr) var/list/command = list() var/list/security = list() var/list/engineering = list() var/list/medical = list() var/list/science = list() var/list/cargo = list() var/list/exploration = list() var/list/civilian = list() var/list/silicons = list() var/list/misc = list() var/list/offduty = list() var/list/talon = list() var/list/trade = list() for(var/datum/data/record/R in data_core.general) var/name = R.fields["name"] var/rank = R.fields["rank"] var/real_rank = make_list_rank(R.fields["real_rank"]) if(SSjob.is_job_in_department(real_rank, DEPARTMENT_TALON)) // Not touching this for now as I dont know if it will break things -Bloop talon[name] = rank continue if(SSjob.is_job_in_department(real_rank, DEPARTMENT_TRADE)) trade[name] = rank continue if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SECURITY)) security[name] = rank else if(SSjob.is_job_in_department(real_rank, DEPARTMENT_ENGINEERING)) engineering[name] = rank else if(SSjob.is_job_in_department(real_rank, DEPARTMENT_MEDICAL)) medical[name] = rank else if(SSjob.is_job_in_department(real_rank, DEPARTMENT_RESEARCH)) science[name] = rank else if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO)) cargo[name] = rank else if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN)) civilian[name] = rank else misc[name] = rank // mixed departments, /datum/department when? if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND)) command[name] = rank if(SSjob.is_job_in_department(real_rank, DEPARTMENT_PLANET)) exploration[name] = rank if(SSjob.is_job_in_department(real_rank, DEPARTMENT_OFFDUTY)) offduty[name] = rank // Synthetics don't have actual records, so we will pull them from here. for(var/mob/living/silicon/ai/ai in GLOB.mob_list) silicons[ai.name] = "Artificial Intelligence" for(var/mob/living/silicon/robot/robot in GLOB.mob_list) // No combat/syndicate cyborgs, no drones, and no AI shells. if(!robot.scrambledcodes && !robot.shell && !(robot.module && robot.module.hide_on_manifest)) silicons[robot.name] = "[robot.modtype] [robot.braintype]" . = list() if(command.len) .["Command"] = command if(security.len) .["Security"] = security if(engineering.len) .["Engineering"] = engineering if(medical.len) .["Medical"] = medical if(science.len) .["Science"] = science if(cargo.len) .["Cargo"] = cargo if(exploration.len) .["Exploration"] = exploration if(civilian.len) .["Civilian"] = civilian if(silicons.len) .["Silicons"] = silicons if(misc.len) .["Misc"] = misc if(offduty.len) .["Off Duty"] = offduty if(talon.len) .["Talon"] = talon if(trade.len) .["Trade"] = trade return json_encode(.) /datum/world_topic/jsonrevision keyword = "jsonrevision" /datum/world_topic/jsonrevision/Run(list/input, addr) var/datum/getrev/revdata = GLOB.revdata var/list/data = list( "date" = copytext(revdata.date, 1, 11), "dd_version" = world.byond_version, "dd_build" = world.byond_build, "dm_version" = DM_VERSION, "dm_build" = DM_BUILD, "revision" = revdata.commit, "testmerge_base_url" = "[CONFIG_GET(string/githuburl)]/pull/" ) if (revdata.testmerge.len) for (var/datum/tgs_revision_information/test_merge/TM in revdata.testmerge) data["testmerges"] += list(list( "id" = TM.number, "desc" = TM.title, "author" = TM.author )) return json_encode(data) /datum/world_topic/status keyword = "status" /datum/world_topic/status/Run(list/input, addr) if(!key_valid) //If we have a key, then it's safe to trust that this isn't a malicious packet. Also prevents the extra info from leaking if(GLOB.topic_status_lastcache >= world.time) return GLOB.topic_status_cache GLOB.topic_status_lastcache = world.time + 5 . = list() .["version"] = game_version .["mode"] = master_mode .["respawn"] = config_legacy.abandon_allowed .["enter"] = config_legacy.enter_allowed .["vote"] = config_legacy.allow_vote_mode .["ai"] = config_legacy.allow_ai .["host"] = host || null .["round_id"] = GLOB.round_id .["players"] = GLOB.clients.len .["revision"] = GLOB.revdata.commit .["revision_date"] = GLOB.revdata.date var/list/adm = get_admin_counts() var/list/presentmins = adm["present"] var/list/afkmins = adm["afk"] .["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho //.["gamestate"] = SSticker.current_state //.["map_name"] = SSmapping.config?.map_name || "Loading..." //if(key_valid) //.["active_players"] = get_active_player_count() /* if(SSticker.HasRoundStarted()) .["real_mode"] = SSticker.mode.name // Key-authed callers may know the truth behind the "secret" */ .["security_level"] = get_security_level() // .["round_duration"] = SSticker ? round((world.time-SSticker.SSticker.round_start_time)/10) : 0 // // Amount of world's ticks in seconds, useful for calculating round duration .["stationtime"] = stationtime2text() .["roundduration"] = roundduration2text() //Time dilation stats. .["time_dilation_current"] = SStime_track.time_dilation_current .["time_dilation_avg"] = SStime_track.time_dilation_avg .["time_dilation_avg_slow"] = SStime_track.time_dilation_avg_slow .["time_dilation_avg_fast"] = SStime_track.time_dilation_avg_fast /* if(SSshuttle && SSshuttle.emergency) .["shuttle_mode"] = SSshuttle.emergency.mode // Shuttle status, see /__DEFINES/stat.dm .["shuttle_timer"] = SSshuttle.emergency.timeLeft() // Shuttle timer, in seconds */ if(!key_valid) GLOB.topic_status_cache = .