From fed38ec2c8b2f283aeae279e89242b96f4e1bc54 Mon Sep 17 00:00:00 2001 From: Letter N <24603524+LetterN@users.noreply.github.com> Date: Tue, 27 Jan 2026 02:52:19 +0800 Subject: [PATCH] update tgs commands (#7511) --- code/__HELPERS/chat.dm | 18 +-- code/__HELPERS/game.dm | 16 ++- code/controllers/subsystem/ticker.dm | 6 +- code/modules/admin/chat_commands.dm | 155 +++++++++++++------------- code/modules/admin/verbs/adminhelp.dm | 4 +- 5 files changed, 106 insertions(+), 93 deletions(-) diff --git a/code/__HELPERS/chat.dm b/code/__HELPERS/chat.dm index 94982ca90fb..eb97735b983 100644 --- a/code/__HELPERS/chat.dm +++ b/code/__HELPERS/chat.dm @@ -36,42 +36,46 @@ */ /** - * Sends a message to TGS chat channels. + * Asynchronously sends a message to TGS chat channels. * - * message - The message to send. + * message - The [/datum/tgs_message_content] to send. * channel_tag - Required. If "", the message with be sent to all connected (Game-type for TGS3) channels. Otherwise, it will be sent to TGS4 channels with that tag (Delimited by ','s). + * admin_only - Determines if this communication can only be sent to admin only channels. */ -/proc/send2chat(message, channel_tag) +/proc/send2chat(datum/tgs_message_content/message, channel_tag, admin_only = FALSE) + set waitfor = FALSE if(channel_tag == null || !world.TgsAvailable()) return var/datum/tgs_version/version = world.TgsVersion() if(channel_tag == "" || version.suite == 3) - world.TgsTargetedChatBroadcast(message, FALSE) + world.TgsTargetedChatBroadcast(message, admin_only) return var/list/channels_to_use = list() for(var/I in world.TgsChatChannelInfo()) var/datum/tgs_chat_channel/channel = I var/list/applicable_tags = splittext(channel.custom_tag, ",") - if(channel_tag in applicable_tags) + if((!admin_only || channel.is_admin_channel) && (channel_tag in applicable_tags)) channels_to_use += channel if(channels_to_use.len) world.TgsChatBroadcast(message, channels_to_use) /** - * Sends a message to TGS admin chat channels. + * Asynchronously sends a message to TGS admin chat channels. * * category - The category of the mssage. * message - The message to send. */ /proc/send2adminchat(category, message, embed_links = FALSE) + set waitfor = FALSE + category = replacetext(replacetext(category, "\proper", ""), "\improper", "") message = replacetext(replacetext(message, "\proper", ""), "\improper", "") if(!embed_links) message = GLOB.has_discord_embeddable_links.Replace(replacetext(message, "`", ""), " ```$1``` ") - world.TgsTargetedChatBroadcast("[category] | [message]", TRUE) + world.TgsTargetedChatBroadcast(new /datum/tgs_message_content("[category] | [message]"), TRUE) /// Handles text formatting for item use hints in examine text #define EXAMINE_HINT(text) ("" + text + "") diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index aa3ce4be3a3..e9448f9f1f2 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -568,8 +568,8 @@ return hear ///Get active players who are playing in the round -/proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE) - var/active_players = 0 +/proc/get_active_player_list(alive_check = FALSE, afk_check = FALSE, human_check = FALSE) + var/list/active_players = list() for(var/mob/player_mob as anything in GLOB.player_list) if(!player_mob?.client) continue @@ -582,8 +582,12 @@ if(isnewplayer(player_mob)) // exclude people in the lobby continue if(isobserver(player_mob)) // Ghosts are fine if they were playing once (didn't start as observers) - // var/mob/observer/dead/ghost_player = player_mob - // if(ghost_player.started_as_observer) // Exclude people who started as observers - continue - active_players++ + var/mob/observer/dead/ghost_player = player_mob + if(ghost_player.started_as_observer) // Exclude people who started as observers + continue + active_players += player_mob return active_players + +///Counts active players who are playing in the round +/proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE) + return length(get_active_player_list(alive_check, afk_check, human_check)) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 3259b8bc40f..4f344f2258f 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -111,12 +111,11 @@ SUBSYSTEM_DEF(ticker) if(blackbox) blackbox.save_all_data_to_sql() - send2irc("Server", "A round of [mode.name] just ended.") if(CONFIG_GET(string/chat_roundend_notice_tag)) var/broadcastmessage = "The round has ended." if(CONFIG_GET(string/chat_reboot_role)) broadcastmessage += "\n\n<@&[CONFIG_GET(string/chat_reboot_role)]>, the server will reboot shortly!" - send2chat(broadcastmessage, CONFIG_GET(string/chat_roundend_notice_tag)) + send2chat(new /datum/tgs_message_content(broadcastmessage), CONFIG_GET(string/chat_roundend_notice_tag)) SSdbcore.SetRoundEnd() SSpersistence.SavePersistence() @@ -125,7 +124,7 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/on_mc_init_finish() - send2irc("Server lobby is loaded and open at byond://[config_legacy.serverurl ? config_legacy.serverurl : (config_legacy.server ? config_legacy.server : "[world.address]:[world.port]")]") + send2chat(new /datum/tgs_message_content("Server lobby is loaded and open at byond://[config_legacy.serverurl ? config_legacy.serverurl : (config_legacy.server ? config_legacy.server : "[world.address]:[world.port]")]")) to_chat(world, "Welcome to the pregame lobby!") to_chat(world, "Please set up your character and select ready. The round will start in [CONFIG_GET(number/lobby_countdown)] seconds.") SEND_SOUND(world, sound('sound/misc/server-ready.ogg', volume = 100)) @@ -552,6 +551,7 @@ SUBSYSTEM_DEF(ticker) to_chat(world, "


The round has ended.
") log_game("The round has ended.") + send2adminchat("Server", "Round just ended.") for(var/datum/callback/roundend_callbacks as anything in round_end_events) roundend_callbacks.InvokeAsync() diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index d64a78cb689..112fdbd796d 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -1,45 +1,17 @@ -#define IRC_STATUS_THROTTLE 5 - -/datum/tgs_chat_command/ircstatus - name = "status" - help_text = "Gets the admincount, playercount, gamemode, and true game mode of the server" +/datum/tgs_chat_command/reload_admins + name = "reload_admins" + help_text = "Forces the server to reload admins." admin_only = TRUE - var/last_irc_status = 0 -/datum/tgs_chat_command/ircstatus/Run(datum/tgs_chat_user/sender, params) - var/rtod = REALTIMEOFDAY - if(rtod - last_irc_status < IRC_STATUS_THROTTLE) - return - last_irc_status = rtod - var/list/adm = get_admin_counts() - var/list/allmins = adm["total"] - var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " - status += "Players: [GLOB.clients.len]" //(Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode ? SSticker.mode.name : "Not started"]." - return status +/datum/tgs_chat_command/reload_admins/Run(datum/tgs_chat_user/sender, params) + ReloadAsync() + log_admin("[sender.friendly_name] reloaded admins via chat command.") + message_admins("[sender.friendly_name] reloaded admins via chat command.") + return "Admins reloaded." -/datum/tgs_chat_command/irccheck - name = "check" - help_text = "Gets the playercount, gamemode, and address of the server" - var/last_irc_check = 0 - -/datum/tgs_chat_command/irccheck/Run(datum/tgs_chat_user/sender, params) - var/rtod = REALTIMEOFDAY - if(rtod - last_irc_check < IRC_STATUS_THROTTLE) - return - last_irc_check = rtod - var/server = null //CONFIG_GET(string/server) - //return "[round_id ? "Round #[round_id]: " : ""][clients.len] players on [SSmapping.config_legacy.map_name], Mode: [master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]" - var/current_state - switch(SSticker.current_state) - if(GAME_STATE_PREGAME) - current_state = "pregame" - if(GAME_STATE_SETTING_UP) - current_state = "starting" - if(GAME_STATE_PLAYING) - current_state = "active" - if(GAME_STATE_FINISHED) - current_state = "finishing" - return "[GLOB.clients.len] players on [(LEGACY_MAP_DATUM).name], Mode: [master_mode]; round [current_state] -- Duration [roundduration2text()] -- [server ? server : "[world.internet_address]:[world.port]"]" +/datum/tgs_chat_command/reload_admins/proc/ReloadAsync() + set waitfor = FALSE + load_admins() /datum/tgs_chat_command/ahelp name = "ahelp" @@ -49,7 +21,7 @@ /datum/tgs_chat_command/ahelp/Run(datum/tgs_chat_user/sender, params) var/list/all_params = splittext(params, " ") if(all_params.len < 2) - return "Insufficient parameters" + return new /datum/tgs_message_content("Insufficient parameters") var/target = all_params[1] all_params.Cut(1, 2) var/id = text2num(target) @@ -58,10 +30,8 @@ if(AH) target = AH.initiator_ckey else - return "Ticket #[id] not found!" - var/res = IrcPm(target, all_params.Join(" "), sender.friendly_name) - if(res != "Message Successful") - return res + return new /datum/tgs_message_content("Ticket #[id] not found!") + return new /datum/tgs_message_content(IrcPm(target, all_params.Join(" "), sender.friendly_name)) /datum/tgs_chat_command/namecheck name = "namecheck" @@ -71,10 +41,10 @@ /datum/tgs_chat_command/namecheck/Run(datum/tgs_chat_user/sender, params) params = trim(params) if(!params) - return "Insufficient parameters" + return new /datum/tgs_message_content("Insufficient parameters") log_admin("Chat Name Check: [sender.friendly_name] on [params]") message_admins("Name checking [params] from [sender.friendly_name]") - return keywords_lookup(params, 1) + return new /datum/tgs_message_content(keywords_lookup(params, 1)) /datum/tgs_chat_command/adminwho name = "adminwho" @@ -82,22 +52,7 @@ admin_only = TRUE /datum/tgs_chat_command/adminwho/Run(datum/tgs_chat_user/sender, params) - return ircadminwho() - -GLOBAL_LIST(round_end_notifiees) - -/datum/tgs_chat_command/endnotify - name = "notify" - help_text = "Pings the invoker when the round ends" - admin_only = FALSE - -/datum/tgs_chat_command/endnotify/Run(datum/tgs_chat_user/sender, params) - //if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted()) - if(SSticker.current_state == GAME_STATE_FINISHED) - return "[sender.mention], the round has already ended!" - LAZYINITLIST(GLOB.round_end_notifiees) - GLOB.round_end_notifiees[sender.mention] = TRUE - return "I will notify [sender.mention] when the round ends." + return new /datum/tgs_message_content(tgsadminwho()) /datum/tgs_chat_command/sdql name = "sdql" @@ -106,29 +61,79 @@ GLOBAL_LIST(round_end_notifiees) /datum/tgs_chat_command/sdql/Run(datum/tgs_chat_user/sender, params) if(GLOB.AdminProcCaller) - return "Unable to run query, another admin proc call is in progress. Try again later." + return new /datum/tgs_message_content("Unable to run query, another admin proc call is in progress. Try again later.") GLOB.AdminProcCaller = "CHAT_[sender.friendly_name]" //_ won't show up in ckeys so it'll never match with a real admin var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller) GLOB.AdminProcCaller = null if(!results) - return "Query produced no output" + return new /datum/tgs_message_content("Query produced no output") var/list/text_res = results.Copy(1, 3) var/list/refs = results.len > 3 ? results.Copy(4) : null - . = "[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]" + return new /datum/tgs_message_content("[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]") -/datum/tgs_chat_command/reload_admins - name = "reload_admins" - help_text = "Forces the server to reload admins." +/datum/tgs_chat_command/tgsstatus + name = "status" + help_text = "Gets the admincount, playercount, gamemode, and true game mode of the server" admin_only = TRUE -/datum/tgs_chat_command/reload_admins/Run(datum/tgs_chat_user/sender, params) - ReloadAsync() - log_admin("[sender.friendly_name] reloaded admins via chat command.") - return "Admins reloaded." +/datum/tgs_chat_command/tgsstatus/Run(datum/tgs_chat_user/sender, params) + var/list/adm = get_admin_counts() + var/list/allmins = adm["total"] + var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " + status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(FALSE, TRUE, FALSE)]). Round has [SSticker.HasRoundStarted() ? "" : "not "]started." + return new /datum/tgs_message_content(status) -/datum/tgs_chat_command/reload_admins/proc/ReloadAsync() - set waitfor = FALSE - load_admins() +// code/modules/discord/tgs_commands.dm +/datum/tgs_chat_command/tgscheck + name = "check" + help_text = "Gets the playercount, gamemode, and address of the server" + +/datum/tgs_chat_command/tgscheck/Run(datum/tgs_chat_user/sender, params) + var/server = config_legacy.serverurl || config_legacy.server + return new /datum/tgs_message_content("[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [(LEGACY_MAP_DATUM).name]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]") + +/datum/tgs_chat_command/gameversion + name = "gameversion" + help_text = "Gets the version details from the show-server-revision verb, basically" + +/datum/tgs_chat_command/gameversion/Run(datum/tgs_chat_user/sender, params) + var/list/msg = list("") + msg += "BYOND Server Version: [world.byond_version].[world.byond_build] (Compiled with: [DM_VERSION].[DM_BUILD])\n" + + if (!GLOB.revdata) + msg += "No revision information found." + else + msg += "Revision [copytext_char(GLOB.revdata.commit, 1, 9)]" + if (GLOB.revdata.date) + msg += " compiled on '[GLOB.revdata.date]'" + + if(GLOB.revdata.originmastercommit) + msg += ", from origin commit: <[CONFIG_GET(string/githuburl)]/commit/[GLOB.revdata.originmastercommit]>" + + if(GLOB.revdata.testmerge.len) + msg += "\n" + for(var/datum/tgs_revision_information/test_merge/PR as anything in GLOB.revdata.testmerge) + msg += "PR #[PR.number] at [copytext_char(PR.head_commit, 1, 9)] [PR.title].\n" + if (PR.url) + msg += "<[PR.url]>\n" + return new /datum/tgs_message_content(msg.Join("")) + +GLOBAL_LIST(round_end_notifiees) +/datum/tgs_chat_command/endnotify + name = "notify" + help_text = "Pings the invoker when the round ends" + admin_only = FALSE + +/datum/tgs_chat_command/endnotify/Run(datum/tgs_chat_user/sender, params) + //if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted()) + if(SSticker.current_state == GAME_STATE_FINISHED) + return new /datum/tgs_message_content("[sender.mention], the round has already ended!") + LAZYINITLIST(GLOB.round_end_notifiees) + if (GLOB.round_end_notifiees[sender.mention]) + GLOB.round_end_notifiees[sender.mention] = FALSE + return new /datum/tgs_message_content("You will no longer be notified when the server restarts") + GLOB.round_end_notifiees[sender.mention] = TRUE + return new /datum/tgs_message_content("You will now be notified when the server restarts") /datum/tgs_chat_command/whitelist name = "whitelist" diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 0f0ace2e845..11ffa27882c 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -613,7 +613,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick/ahelp) msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "") world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE) -/proc/ircadminwho() +/proc/tgsadminwho() var/list/message = list("Admins: ") var/list/admin_keys = list() for(var/adm in GLOB.admins) @@ -621,7 +621,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick/ahelp) admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]" for(var/admin in admin_keys) - if(LAZYLEN(admin_keys) > 1) + if(LAZYLEN(message) > 1) message += ", [admin]" else message += "[admin]"