From 3d183d7262f75d80adefc4794bce54adcdeef7db Mon Sep 17 00:00:00 2001 From: Wildkins Date: Mon, 9 Feb 2026 18:20:48 -0500 Subject: [PATCH] Begin, the Lag Wars Have (#21839) image you take a tiny little two year LOA and this happens this PR hits some large lag culprits: - UpdateOverlays() getting spammed by human/update_icon. This was 0.85% of server CPU time during the event. Doesn't sound like a whole lot but it's insane. 99% of it was caused by sloppy duplicate calls of update_icon in set_dir (as well as update icon itself!). Refactored to stop that - Makes Follow menu update manually, which cuts down on the 2.8 million REF() calls it made during the event. This was ~1% of CPU time including ui_data as well. - Gets rid of a bunch of random runtimes and some lighting-related harddels. - NanoUIs now clean themselves up when their owner qdels rather than forcing the owner to do REF(src) and close all matching UIs. saves us ~0.1% server cpu time! wowza! --- code/datums/datum.dm | 4 -- code/game/machinery/doors/windowdoor.dm | 2 +- code/game/objects/items.dm | 7 +-- code/modules/mob/abstract/ghost/ghost.dm | 6 +- code/modules/mob/living/carbon/human/death.dm | 4 +- code/modules/mob/living/carbon/human/human.dm | 2 +- .../mob/living/carbon/human/human_defines.dm | 1 - .../mob/living/carbon/human/human_movement.dm | 4 +- .../living/carbon/human/species/species.dm | 4 +- .../mob/living/carbon/human/update_icons.dm | 61 ++++++++----------- code/modules/nano/modules/follow_menu.dm | 12 +++- code/modules/nano/nanoui.dm | 2 +- code/modules/organs/subtypes/standard.dm | 11 ++-- .../Chemistry-Reagents-Drugs.dm | 2 +- code/modules/shuttles/shuttle_console.dm | 1 + code/modules/vehicles/vehicle.dm | 6 +- html/changelogs/JohnWildkins-cooked.yml | 24 ++++++++ tgui/packages/tgui/interfaces/FollowMenu.tsx | 25 ++++---- .../ShuttleControlConsoleMultiLift.tsx | 5 +- 19 files changed, 103 insertions(+), 80 deletions(-) create mode 100644 html/changelogs/JohnWildkins-cooked.yml diff --git a/code/datums/datum.dm b/code/datums/datum.dm index cf0d7816d5b..7066ac6d57e 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -115,10 +115,6 @@ if (!isturf(src)) cleanup_events(src) - var/ui_key = REF(src) - if(LAZYISIN(SSnanoui.open_uis, ui_key)) - SSnanoui.close_uis(src) - //BEGIN: ECS SHIT var/list/dc = _datum_components if(dc) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 6a0c4ea0ea2..a9b7fec7af2 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -155,7 +155,7 @@ take_damage(25) return else - return attackby(user, user) + return attackby(null, user) /obj/machinery/door/window/emag_act(var/remaining_charges, var/mob/user) if (density && operable()) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 7d21ebb7b6d..adc75a9ffc5 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -257,10 +257,7 @@ /obj/item/Destroy() if(ismob(loc)) var/mob/m = loc - m.drop_from_inventory(src) - m.update_inv_r_hand() - m.update_inv_l_hand() - src.loc = null + m.drop_from_inventory(src, null) if(!QDELETED(action)) QDEL_NULL(action) // /mob/living/proc/handle_actions() creates it, for ungodly reasons @@ -930,7 +927,7 @@ GLOBAL_LIST_INIT(slot_flags_enumeration, list( user.langchat_speech("holds up [src].", viewers, GLOB.all_languages, skip_language_check = TRUE, animation_style = LANGCHAT_FAST_POP, additional_styles = list("langchat_small", "emote")) for (var/mob/M in viewers) if(!user.is_invisible_to(M)) - M.show_message("[user] holds up [icon2html(src, viewers)] [src]. Take a closer look.",1) + M.show_message("[user] holds up [icon2html(src, M)] [src]. Take a closer look.",1) /mob/living/carbon/verb/showoff() set name = "Show Held Item" diff --git a/code/modules/mob/abstract/ghost/ghost.dm b/code/modules/mob/abstract/ghost/ghost.dm index 86da2ead88e..9c053c0dbd6 100644 --- a/code/modules/mob/abstract/ghost/ghost.dm +++ b/code/modules/mob/abstract/ghost/ghost.dm @@ -132,13 +132,12 @@ set category = "Ghost" set desc = "Follow and haunt a mob." - var/datum/tgui_module/follow_menu/GM = new /datum/tgui_module/follow_menu(usr) - GM.ui_interact(usr) + GLOB.follow_menu.ui_interact(src) // This is the ghost's follow verb with an argument /mob/abstract/ghost/proc/ManualFollow(var/atom/movable/target) if(!target) - return + return FALSE //Stops orbit if there's any; TG doesn't do this, but if you don't it breaks the orbiting reference //if you are jumping from one mob to another, hence why we're doing it here @@ -154,6 +153,7 @@ to_chat(src, SPAN_NOTICE("Now following \the [target].")) update_sight() + return TRUE /mob/abstract/ghost/proc/update_sight() //if they are on a restricted level, then set the ghost vision for them. diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index c30ca732347..5ff5ff87397 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -109,9 +109,9 @@ var/datum/sprite_accessory/hair/hair = GLOB.hair_styles_list[h_style] var/datum/sprite_accessory/facial_hair/facial = GLOB.facial_hair_styles_list[f_style] - if(!facial.keep_as_skeleton && f_style) + if(facial && !facial.keep_as_skeleton) f_style = "Shaved" - if(!hair.keep_as_skeleton && h_style) + if(hair && !hair.keep_as_skeleton) h_style = "Bald" update_hair(0) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c662494a0ca..19c7ce3e6c5 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1466,7 +1466,7 @@ self = 1 if ((src.species.flags & NO_BLOOD) || (status_flags & FAKEDEATH)) - to_chat(usr, SPAN_WARNING(self ? "You have no pulse." : "[src] has no pulse!")) + to_chat(usr, SPAN_WARNING("[self ? "You have" : "[src] has"] no pulse!")) return if(!self) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index eec74a16945..fc14e29f070 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -38,7 +38,6 @@ var/size_multiplier = 1 //multiplier for the mob's icon size var/damage_multiplier = 1 //multiplies melee combat damage - var/icon_update = 1 //whether icon updating shall take place var/default_lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index fe8fbe30f97..386028d36a5 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -122,9 +122,9 @@ /mob/living/carbon/human/set_dir(var/new_dir, ignore_facing_dir = FALSE) . = ..() if(. && tail_style) - update_tail_showing(1) + update_tail_showing(!lying) if(lying) - update_icon(forceDirUpdate = TRUE) + update_icon(TRUE) /mob/living/carbon/human/Move() . = ..() diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 4e0523f1039..203de09a486 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -995,7 +995,9 @@ /datum/species/proc/handle_stance_damage(var/mob/living/carbon/human/H, var/damage_only = FALSE) var/static/support_limbs = list( BP_L_LEG = BP_R_LEG, - BP_L_FOOT = BP_R_FOOT + BP_L_FOOT = BP_R_FOOT, + BP_R_LEG = BP_L_LEG, + BP_R_FOOT = BP_L_FOOT ) var/has_opposite_limb = FALSE diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 4f0eb036d2d..7398053cfa4 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -104,26 +104,29 @@ There are several things that need to be remembered: var/list/overlays_raw[TOTAL_LAYERS] // Our set of "raw" overlays that can be modified, but cannot be directly applied to the mob without preprocessing. var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed -#define UPDATE_ICON_IGNORE_DIRECTION_UPDATE -1 - // Updates overlays from overlays_raw. /mob/living/carbon/human/update_icon(var/forceDirUpdate = FALSE) if (QDELETED(src)) return // No point. + var/update_lying = (lying_prev != lying) || forceDirUpdate || size_multiplier != 1 + var/draw_specific_icon = (!lying || species.prone_icon) + + if(update_lying && draw_specific_icon) + update_inv_l_hand(FALSE) + update_inv_r_hand(FALSE) + update_hud() //TODO: remove the need for this - ClearOverlays() if(cloaked) icon = 'icons/mob/human.dmi' icon_state = "body_cloaked" - AddOverlays(list(overlays_raw[L_HAND_LAYER], overlays_raw[R_HAND_LAYER])) - - else if (icon_update) + SetOverlays(list(overlays_raw[L_HAND_LAYER], overlays_raw[R_HAND_LAYER])) + else + var/list/ovr = list() if (icon != stand_icon) icon = stand_icon - var/list/ovr = list() // We manually add each element instead of just using Copy() so that lists are appended instead of inserted. for (var/item in overlays_raw) if (item) @@ -137,18 +140,20 @@ There are several things that need to be remembered: var/icon/aura_overlay = icon(A.icon, icon_state = A.icon_state) ovr += aura_overlay - AddOverlays(ovr) - - if (((lying_prev != lying) || forceDirUpdate || size_multiplier != 1) && forceDirUpdate != UPDATE_ICON_IGNORE_DIRECTION_UPDATE) - if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. - var/matrix/M = matrix() + SetOverlays(ovr) + if(update_lying) //Only rotate them if we're not drawing a specific icon for being prone. + var/matrix/M = matrix() + M.Scale(size_multiplier) + if(draw_specific_icon) + M.Translate(0, 16*(size_multiplier-1)) + animate(src, transform = M, time = ANIM_LYING_TIME) + else switch(src.dir) if(SOUTH,EAST) M.Turn(90) else M.Turn(-90) - M.Scale(size_multiplier) M.Translate(1,-6) animate(src, transform = M, time = (forceDirUpdate ? 0 : ANIM_LYING_TIME)) @@ -157,15 +162,6 @@ There are several things that need to be remembered: if(istype(src.r_hand, /obj/item/gun) && lying) HeldObjectDirTransform(slot_r_hand, src.dir) - else - update_inv_l_hand(FALSE) - update_inv_r_hand(FALSE) - update_icon(UPDATE_ICON_IGNORE_DIRECTION_UPDATE) - var/matrix/M = matrix() - M.Scale(size_multiplier) - M.Translate(0, 16*(size_multiplier-1)) - animate(src, transform = M, time = ANIM_LYING_TIME) - UpdateOverlays() lying_prev = lying @@ -196,9 +192,7 @@ There are several things that need to be remembered: animate(item_image, transform = item_transform) overlays_raw[layer] = item_image - update_icon(UPDATE_ICON_IGNORE_DIRECTION_UPDATE) - -#undef UPDATE_ICON_IGNORE_DIRECTION_UPDATE + update_icon() //DAMAGE OVERLAYS //constructs damage icon for each organ from mask * damage field and saves it in our overlays_raw list (as a list of icons). @@ -1245,7 +1239,7 @@ There are several things that need to be remembered: overlays_raw[L_HAND_LAYER] = null if(update_icons) - update_icon(forceDirUpdate = TRUE) + update_icon(TRUE) /mob/living/carbon/human/update_inv_r_hand(update_icons = TRUE) if (QDELETED(src)) @@ -1284,7 +1278,7 @@ There are several things that need to be remembered: overlays_raw[R_HAND_LAYER] = null if(update_icons) - update_icon(forceDirUpdate = TRUE) + update_icon(TRUE) /mob/living/carbon/human/update_inv_wrists(var/update_icons=1) if (QDELETED(src)) @@ -1389,7 +1383,7 @@ There are several things that need to be remembered: if(species.tail && !(mutations & HUSK) && !(mutations & SKELETON) && !(wear_suit && wear_suit.flags_inv & HIDETAIL)) var/icon/tail_s = get_tail_icon() overlays_raw[tail_layer] = image(tail_s, icon_state = "[tail_style]_s") - animate_tail_reset() + animate_tail_reset(FALSE) update_tail_accessory(FALSE) if(update_icons) @@ -1414,7 +1408,7 @@ There are several things that need to be remembered: return tail_icon -/mob/living/carbon/human/proc/set_tail_state(var/mob_state) +/mob/living/carbon/human/proc/set_tail_state(var/mob_state, var/update = TRUE) if(!tail_style) return @@ -1428,8 +1422,7 @@ There are several things that need to be remembered: if(tail_overlay && species.tail_animation) if(tail_overlay.icon_state != mob_state) tail_overlay.icon_state = mob_state - update_tail_accessory() - update_icon() + update_tail_accessory(update) return tail_overlay return null @@ -1461,11 +1454,11 @@ There are several things that need to be remembered: /mob/living/carbon/human/proc/animate_tail_fast() set_tail_state("[tail_style]_loop") -/mob/living/carbon/human/proc/animate_tail_reset() +/mob/living/carbon/human/proc/animate_tail_reset(var/update = TRUE) if(stat != DEAD && !lying) - set_tail_state("[tail_style]_idle") + set_tail_state("[tail_style]_idle", update) else - set_tail_state("[tail_style]_static") + set_tail_state("[tail_style]_static", update) /mob/living/carbon/human/proc/animate_tail_stop(var/update_icons=1) set_tail_state("[tail_style]_static") diff --git a/code/modules/nano/modules/follow_menu.dm b/code/modules/nano/modules/follow_menu.dm index 87b033df6f1..657895e3718 100644 --- a/code/modules/nano/modules/follow_menu.dm +++ b/code/modules/nano/modules/follow_menu.dm @@ -1,3 +1,5 @@ +GLOBAL_DATUM_INIT(follow_menu, /datum/tgui_module/follow_menu, new) + /datum/tgui_module/follow_menu/ui_interact(var/mob/user, var/datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -14,9 +16,15 @@ return if(action == "follow_target") - ghost.ManualFollow(locate(params["follow_target"]) in GLOB.mob_list) + if(!ghost.ManualFollow(locate(params["follow_target"]) in GLOB.mob_list)) + to_chat(ghost, SPAN_WARNING("Failed to follow selected target. Refreshing mob list...")) + return TRUE -/datum/tgui_module/follow_menu/ui_data(mob/user) + if(action == "refresh") + ui.send_full_update() + return TRUE + +/datum/tgui_module/follow_menu/ui_static_data(mob/user) var/list/data = list() // Don't worry about this is_mod check being for storytellers as well - all it does is highlight antags in red. var/is_mod = check_rights(R_MOD|R_ADMIN, 0, user) || isstoryteller(user) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 9baa217ba53..c441af104f2 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -519,7 +519,7 @@ nanoui is used to open and update nano browser uis * @return nothing */ /datum/nanoui/process(update = 0) - if (!src_object || !user) + if (QDELETED(src_object) || QDELETED(user)) close() return diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm index 242123f7532..8802cd65738 100644 --- a/code/modules/organs/subtypes/standard.dm +++ b/code/modules/organs/subtypes/standard.dm @@ -194,12 +194,11 @@ /obj/item/organ/external/hand/is_malfunctioning() . = ..() - if(!.) - if(owner.is_mechanical()) - var/actuator_type = limb_name == BP_L_HAND ? BP_ACTUATORS_LEFT : BP_ACTUATORS_RIGHT - var/obj/item/organ/internal/machine/actuators/actuator = owner.internal_organs_by_name[actuator_type] - if(!actuator || (actuator.status & ORGAN_DEAD)) - return TRUE + if(!. && owner?.is_mechanical()) + var/actuator_type = limb_name == BP_L_HAND ? BP_ACTUATORS_LEFT : BP_ACTUATORS_RIGHT + var/obj/item/organ/internal/machine/actuators/actuator = owner.internal_organs_by_name[actuator_type] + if(!actuator || (actuator.status & ORGAN_DEAD)) + return TRUE /obj/item/organ/external/hand/take_damage(brute, burn, damage_flags, used_weapon, list/forbidden_limbs, silent) . = ..() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm index d0108be2878..921f4a0c6c3 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm @@ -312,7 +312,7 @@ M.hallucination = max(M.hallucination, drug_strength) if(prob(15)) - to_chat(SPAN_GOOD(pick("The floor is melting...", "Everything is so much brighter! Wow!", "Everything is shifting around you."))) + to_chat(M, SPAN_GOOD(pick("The floor is melting...", "Everything is so much brighter! Wow!", "Everything is shifting around you."))) /singleton/reagent/drugs/night_juice diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm index 2966904f98f..75ada22dd0f 100644 --- a/code/modules/shuttles/shuttle_console.dm +++ b/code/modules/shuttles/shuttle_console.dm @@ -170,6 +170,7 @@ "can_force" = shuttle.can_force(), "can_rename_ship" = can_rename_ship, "ship_name" = shuttle.name, + "current_location" = shuttle.get_location_name(), ) /obj/machinery/computer/shuttle_control/ui_act(action, params) diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index a9726b238b7..596d0b17b91 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -202,15 +202,13 @@ if(powered && cell?.charge < charge_use && !organic) return FALSE on = TRUE - set_light_range_power_color(initial(light_range)) - set_light_on(on) + set_light(initial(light_range)) update_icon() return TRUE /obj/vehicle/proc/turn_off() on = FALSE - set_light_range_power_color(0) - set_light_on(on) + set_light(0) update_icon() /obj/vehicle/emag_act(var/remaining_charges, mob/user as mob) diff --git a/html/changelogs/JohnWildkins-cooked.yml b/html/changelogs/JohnWildkins-cooked.yml new file mode 100644 index 00000000000..66ddc0a03ea --- /dev/null +++ b/html/changelogs/JohnWildkins-cooked.yml @@ -0,0 +1,24 @@ +# Your name. +author: Wildkins + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Every single datum no longer does REF(src) on /Destroy to see if it has an open nanoui" + - bugfix: "Showing held items no longer causes every recording device to runtime." + - refactor: "Every obj/item/Destroy no longer updates the held mob's icon three times." + - refactor: "Follow menu is now a global UI and should no longer DDOS the server when 50 people have it open" + - refactor: "Follow menu no longer auto-updates the list of mobs while open, use the refresh button." + - bugfix: "Fix runtime when a /human without hair or facial hair would be skeletonized" + - refactor: "Cleaned up human icon update code. Lying / direction changes no longer cause four update_icon calls. Tailed species turning no longer causes six." + - bugfix: "Fix runtime caused by detached / ownerless mechanical hands." + - bugfix: "Fix colorspace runtime." + - bugfix: "Fix lighting harddel caused by using improper handlers for static lights." + - bugfix: "Lifts now grey out the current location, instead of throwing a runtime when you click it." + - bugfix: "Fix runtime when a bloodless/fakedeath mob has their pulse taken." diff --git a/tgui/packages/tgui/interfaces/FollowMenu.tsx b/tgui/packages/tgui/interfaces/FollowMenu.tsx index be852b9a76d..c772734dfa8 100644 --- a/tgui/packages/tgui/interfaces/FollowMenu.tsx +++ b/tgui/packages/tgui/interfaces/FollowMenu.tsx @@ -30,17 +30,20 @@ export const FollowMenu = (props, context) => {
{ - setSearchTerm(value); - }} - value={searchTerm} - /> + <> + { + setSearchTerm(value); + }} + value={searchTerm} + /> +