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.

<img width="394" height="33" alt="image"
src="https://github.com/user-attachments/assets/a973b863-56ad-46f6-ac34-e3cd479dd76d"
/>

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.

<img width="686" height="388" alt="image"
src="https://github.com/user-attachments/assets/e91c96d3-9031-4720-8e21-aa4d4afa84fc"
/>
This commit is contained in:
VMSolidus
2026-07-11 14:32:59 +00:00
committed by GitHub
parent 2122b216ab
commit 5627e02e93
3 changed files with 40 additions and 7 deletions
+27 -7
View File
@@ -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()
@@ -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)