From 818008bca0f28dff511fc2587d882bdcb9002ef2 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:36:44 -0700 Subject: [PATCH] Fixes process_cell runtimes during lazyloading (#96367) ## About The Pull Request I normally really don't like doing this but because this is so in the weeds this is an alt pr. Alt of #96366, I really don't want to add overhead to process_cell(). The issue here is when we request a reservation the turfs are empty()'d which clears them out and places them in SSair's adjacent_turf recalc queue (which will eventually cause an activation to clear out excited groups). We then immediately start maploading, which creates new, uninitialized turfs (that remain in the queue because turf refs are based off position instead of the actual datum). These unintialized turfs are able to interact with the other, yet to be new()'d over turfs in the recalc queue. This causes runtimes. Later, while we initialize the turfs we loaded, we also have interactions between initialized and uninitialized turfs, which also causes runtimes. The solution here is to prevent atmos processing in a loading template. I do that here by first clearing out all relevant turfs from atmos_adjacent_turf lists and deactivating them. We also have to clear them from the recalc queue to prevent "fixing" this problem. Then, after initialize is complete, we requeue them for recalcing, to restore them to a workable state. The underlying problem here is the logic of maploading is kind of designed to run before everything else has initialized. It's something we can dodge, but it will also show up in things that start processing on initialize and expect their turf to immediately be ready for them. S a bit of a mess. Of note, it's technically possible for a turf to be initialized, activate, and then attempt to process with an unitialized neighbor with this solution. My gut fix for this would be using blocks_air to prevent adjacent turfs from being recalculated until after InitializeAtoms is finished, but that breaks turf/open/Initialize where we setup gasmixtures, and I don't want to duplicate that code. So we'll just bite the small risk of runtimes, they won't actually break anything after all just make a bit of noise. ## Why It's Good For The Game Closes #89649 This adds about 110ms of cost to loading the nukie station on my machine (I used line by line macros around the two for loops), which is significant but not huge, and it's cost that can be safely CHECK_TICK'd. I think the cost of actually loading outweighs that significantly enough (6.6s on my machine) that it's fine. I prefer this solution to the alternative of adding guard checks to process_cell because I do not want to add overhead to atmos code, and also I don't like the idea that we cannot reliably prevent this (shuttle code handles it effectively using blocks_air, as an example). Also, it doesn't really resolve the uninitialized bit of this problem, which isn't... good. Technically changes the math on share() too) --- code/datums/lazy_template.dm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/code/datums/lazy_template.dm b/code/datums/lazy_template.dm index d527d46b6d6..41d837993c4 100644 --- a/code/datums/lazy_template.dm +++ b/code/datums/lazy_template.dm @@ -81,6 +81,17 @@ var/turf/bottom_left = reservation.bottom_left_turfs[z_idx] var/turf/top_right = reservation.top_right_turfs[z_idx] + // Make our turfs dead to atmos + // Cache for sonic speed + var/list/to_rebuild = SSair.adjacent_rebuild + for(var/turf/contained_turf as anything in block(bottom_left, top_right)) + SSair.remove_from_active(contained_turf) + to_rebuild -= contained_turf + for(var/turf/sub_turf as anything in contained_turf.atmos_adjacent_turfs) + sub_turf.atmos_adjacent_turfs?.Remove(contained_turf) + contained_turf.atmos_adjacent_turfs?.Cut() + CHECK_TICK + load_map( file(load_path), bottom_left.x, @@ -104,6 +115,10 @@ loaded_atom_movables |= thing SSatoms.InitializeAtoms(loaded_areas + loaded_atom_movables + loaded_turfs) + for(var/turf/turf as anything in loaded_turfs) + CALCULATE_ADJACENT_TURFS(turf, NORMAL_TURF) + CHECK_TICK + SSlighting.setup_static_lighting_if_needed(loaded_turfs) SSmachines.setup_template_powernets(loaded_cables) SSair.setup_template_machinery(loaded_atmospherics)