From 71587c5ad055237bd2be3e3cc93fe5b1a51b9e11 Mon Sep 17 00:00:00 2001 From: Leshana Date: Wed, 15 Mar 2017 18:51:58 -0400 Subject: [PATCH] Fix rooms holding pressure when exposed to space. This happens because edges cease processing when the delta between their zones is small enough. This is normally a fine optimization, but when it results in a room at 4kPa with a window open to space, it breaks imurshuns. Two main changes to solve this problem without too much cpu cost: 1) Stop edges from sleeping if one side is a hard vacuum. This ensures that a zone doesn't freeze at a low-but-non-zero pressure when touching hard vacuum. 2) Prevent #1 from causing the edge to stay alive for ages while pressures asymptotically approach zero as they are repeatedly equalized but only half is dumped to space. (Would happen if ZoneA---ZoneB---Space arrangement exists) by detecting when the total amount of air left is small enough that it would normally sleep anyway, and just setting it to zero. The end outcome is that behavior is mostly the same as before, except when zones have an open path to unsimulated space, they will reach equilibrium at zero instead of semi-random lowish values. --- code/ZAS/ConnectionGroup.dm | 8 ++++++-- code/modules/xgm/xgm_gas_mixture.dm | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/code/ZAS/ConnectionGroup.dm b/code/ZAS/ConnectionGroup.dm index f377efe74fa..94df46ac015 100644 --- a/code/ZAS/ConnectionGroup.dm +++ b/code/ZAS/ConnectionGroup.dm @@ -180,7 +180,8 @@ Class Procs: air_master.mark_zone_update(B) /connection_edge/zone/recheck() - if(!A.air.compare(B.air)) + // Edges with only one side being vacuum need processing no matter how close. + if(!A.air.compare(B.air, vacuum_exception = 1)) air_master.mark_edge_active(src) //Helper proc to get connections for a zone. @@ -235,7 +236,10 @@ Class Procs: air_master.mark_zone_update(A) /connection_edge/unsimulated/recheck() - if(!A.air.compare(air)) + // Edges with only one side being vacuum need processing no matter how close. + // Note: This handles the glaring flaw of a room holding pressure while exposed to space, but + // does not specially handle the less common case of a simulated room exposed to an unsimulated pressurized turf. + if(!A.air.compare(air, vacuum_exception = 1)) air_master.mark_edge_active(src) proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm index 6f17fba409e..cb600f254f7 100644 --- a/code/modules/xgm/xgm_gas_mixture.dm +++ b/code/modules/xgm/xgm_gas_mixture.dm @@ -96,10 +96,16 @@ update_values() +// Used to equalize the mixture between two zones before sleeping an edge. /datum/gas_mixture/proc/equalize(datum/gas_mixture/sharer) var/our_heatcap = heat_capacity() var/share_heatcap = sharer.heat_capacity() + // Special exception: there isn't enough air around to be worth processing this edge next tick, zap both to zero. + if(total_moles + sharer.total_moles <= MINIMUM_AIR_TO_SUSPEND) + gas.Cut() + sharer.gas.Cut() + for(var/g in gas|sharer.gas) var/comb = gas[g] + sharer.gas[g] comb /= volume + sharer.volume @@ -282,9 +288,16 @@ //Checks if we are within acceptable range of another gas_mixture to suspend processing or merge. -/datum/gas_mixture/proc/compare(const/datum/gas_mixture/sample) +/datum/gas_mixture/proc/compare(const/datum/gas_mixture/sample, var/vacuum_exception = 0) if(!sample) return 0 + if(vacuum_exception) + // Special case - If one of the two is zero pressure, the other must also be zero. + // This prevents suspending processing when an air-filled room is next to a vacuum, + // an edge case which is particually obviously wrong to players + if(total_moles == 0 && sample.total_moles != 0 || sample.total_moles == 0 && total_moles != 0) + return 0 + var/list/marked = list() for(var/g in gas) if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \