From 5627e02e93d49c8610a8dcaeacf1aee997e91414 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jul 2026 10:32:59 -0400 Subject: [PATCH] Kill Gas Tank Processing (#22810) This PR nukes the single largest and most common source of unnecessary Process() calls, the Air Tanks. Air tanks now dynamically add and remove themselves from processing only when actually required (such as by being actively used) or they contain a "reactive" gas mixture. Gas tanks made up the overwhelming majority of all process calls, and without them always being on, the Processing subsystem becomes extremely cheap. image I have also tested gas tanks to make sure that they still work, being chargable, dischargable, able to breathe from them, and that opening the valve works. All 4 actions add the gas tank to processing. When the actions are finished, the tank exits processing. image --- .../game/objects/items/weapons/tanks/tanks.dm | 34 +++++++++++++++---- .../atmoalter/portable_atmospherics.dm | 9 +++++ .../hellfirejag-kill-tanks-processing.yml | 4 +++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 html/changelogs/hellfirejag-kill-tanks-processing.yml diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 0266b3b1e24..ebcf816aae2 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -183,6 +183,7 @@ . = TRUE /obj/item/tank/remove_air(amount) + START_PROCESSING(SSprocessing, src) return air_contents.remove(amount) /obj/item/tank/return_air() @@ -190,14 +191,20 @@ /obj/item/tank/assume_air(datum/gas_mixture/giver) air_contents.merge(giver) - + START_PROCESSING(SSprocessing, src) check_status() + update_gauge() return 1 +/obj/item/tank/update_icon() + . = ..() + update_gauge() + /obj/item/tank/proc/remove_air_volume(volume_to_return) if(!air_contents) return null + START_PROCESSING(SSprocessing, src) var/tank_pressure = XGM_PRESSURE(air_contents) if(tank_pressure < distribute_pressure) distribute_pressure = tank_pressure @@ -210,17 +217,29 @@ var/tank_pressure = 0 // we pass tank_pressure around and try not to recalc it unless we have to // this is a very hot proc (~2M calls/hr) - if(air_contents) - tank_pressure = XGM_PRESSURE(air_contents) - air_contents.react() - tank_pressure = check_status(tank_pressure) - if(gauge_icon) - update_gauge(tank_pressure) + if(!air_contents) + update_gauge(tank_pressure) // Just to make sure the tank is marked empty + return PROCESS_KILL // No need to process empty air tanks + + tank_pressure = XGM_PRESSURE(air_contents) + if (!air_contents.react()) + update_gauge(tank_pressure) // Last icon cleanup on no-reaction. + return PROCESS_KILL // No need to continuously process non-reactive gas mixtures. + + tank_pressure = check_status(tank_pressure) + if (!tank_pressure) + update_gauge(tank_pressure) // Last icon cleanup on reaction consuming all the gas + return PROCESS_KILL // No need to continuously process empty gas mixtures. + + update_gauge(tank_pressure) /obj/item/tank/proc/adjust_initial_gas() return /obj/item/tank/proc/update_gauge(gauge_pressure = 0) + if (!gauge_icon) + return + if(air_contents) if(!gauge_pressure) gauge_pressure = XGM_PRESSURE(air_contents) @@ -307,5 +326,6 @@ return QDELETED(src) ? 0 : pressure // if we qdel'd or return 0, something changed and we gotta recalc /obj/item/tank/proc/remove_air_by_flag(flag, amount) + START_PROCESSING(SSprocessing, src) . = air_contents.remove_by_flag(flag, amount) update_icon() diff --git a/code/game/objects/structures/machinery/atmoalter/portable_atmospherics.dm b/code/game/objects/structures/machinery/atmoalter/portable_atmospherics.dm index a3123061f9a..7a73a65be69 100644 --- a/code/game/objects/structures/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/objects/structures/machinery/atmoalter/portable_atmospherics.dm @@ -105,6 +105,15 @@ if (network) network.update = 1 +// This exists because for stupid reasons these machines touch air directly instead of respecting an air tank's procs. +/obj/structure/machinery/portable_atmospherics/Exited(atom/movable/gone, direction) + . = ..() + if(gone == holding) + if(istype(gone, /obj/item/tank)) + var/obj/item/tank/T = gone + T.update_icon() + holding = null + /obj/structure/machinery/portable_atmospherics/attackby(obj/item/attacking_item, mob/user) if ((istype(attacking_item, /obj/item/tank) && !( src.destroyed ))) if (src.holding) diff --git a/html/changelogs/hellfirejag-kill-tanks-processing.yml b/html/changelogs/hellfirejag-kill-tanks-processing.yml new file mode 100644 index 00000000000..c77f4d96a31 --- /dev/null +++ b/html/changelogs/hellfirejag-kill-tanks-processing.yml @@ -0,0 +1,4 @@ +author: Hellfirejag +delete-after: True +changes: + - refactor: "Refactored air tanks to no longer require constant processing when idle."