From 3582aa77bb68d43c1ebbff9e06226bf3089cb07a Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sat, 22 Oct 2022 13:10:22 -0700 Subject: [PATCH] Slightly optimizes reagent splashing (#70709) * Slightly optimizes reagent splashing Ok so like, before, splashing a reagent performed a rudimentary floodfill based off atmos connectivity. This was really slow, because it did it using orange(), and repeated orange()s to cut out JUST the rim, because we needed to ensure things were ordered. I've changed this to use floodfill. I've also moved some code that was in a second loop into the first one, and replaced a repeated in check with a single use of & This is still not optimal for large ranges, because we filter by connectivity first and THEN view, but it's faster for smaller ones. BTW I'm also capping the max spread range at 40x40 tiles. If you want more then 1600 you can rot in hell. This takes the (uncapped range) cost of deconstructing a highcap tank from 40 seconds to 0.16. I hate this codebase * god damn it Co-authored-by: san7890 * whoops that's redundant Co-authored-by: san7890 --- code/modules/reagents/chem_splash.dm | 65 ++++++++++++---------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/code/modules/reagents/chem_splash.dm b/code/modules/reagents/chem_splash.dm index 4b4a95809ab..50d5ed37b47 100644 --- a/code/modules/reagents/chem_splash.dm +++ b/code/modules/reagents/chem_splash.dm @@ -75,51 +75,40 @@ * Arguments: * - [source][/datum/reagents]: The reagents to spread around. * - [epicenter][/atom]: The epicenter/source location of the reagent spread. - * - spread_range: The range in which to spread the reagents. + * - spread_range: The range in which to spread the reagents. Will not go over 20 */ /proc/spread_reagents(datum/reagents/source, atom/epicenter, spread_range) + spread_range = min(spread_range, 20) // Fuck off with trying to do more then this var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread() steam.set_up(10, 0, epicenter) steam.attach(epicenter) steam.start() - - var/list/viewable = view(spread_range, epicenter) - var/list/accessible = list(epicenter) - for(var/i in 1 to spread_range) - var/list/turflist = list() - for(var/turf/T in (orange(i, epicenter) - orange(i-1, epicenter))) - turflist |= T - for(var/turf/T in turflist) - if(!(get_dir(T,epicenter) in GLOB.cardinals) && (abs(T.x - epicenter.x) == abs(T.y - epicenter.y) )) - turflist.Remove(T) - turflist.Add(T) // we move the purely diagonal turfs to the end of the list. - for(var/turf/T in turflist) - if(accessible[T]) - continue - for(var/thing in T.get_atmos_adjacent_turfs(alldir = TRUE)) - var/turf/NT = thing - if(!(NT in accessible)) - continue - if(!(get_dir(T,NT) in GLOB.cardinals)) - continue - accessible[T] = 1 - break - + // This is a basic floodfill algorithm of atmos connected tiles + // Turfs will be stored in the form turf -> TRUE var/chem_temp = source.chem_temp - var/list/reactable = accessible - for(var/turf/T in accessible) - reactable += T - for(var/atom/A in T.get_all_contents()) - if(!(A in viewable)) + var/hot_chem = chem_temp >= 300 + var/list/turflist = list() + var/list/reactable = list() + turflist[epicenter] = TRUE + for(var/i = 1; i <= length(turflist); i++) + var/turf/valid_step = turflist[i] + if(get_dist(valid_step, epicenter) > spread_range) // We are over threshold, don't add anything new and just keep goin + turflist.Cut(i, i+1) + i-- + continue + + for(var/turf/lad as anything in valid_step.atmos_adjacent_turfs) + if(turflist[lad]) continue - reactable |= A - if(chem_temp >= 300) - T.hotspot_expose(chem_temp*2, 5) - if(!reactable.len) //Nothing to react with. Probably means we're in nullspace. - return - for(var/thing in reactable) - var/atom/A = thing - var/distance = max(1, get_dist(A, epicenter)) + turflist[lad] = TRUE + + reactable += valid_step.get_all_contents() // Yes this means multitile objects double react. I don't care. skill issue + if(hot_chem) + valid_step.hotspot_expose(chem_temp*2, 5) + + // Remove anything we can't see + for(var/atom/thing as anything in (dview(spread_range, epicenter) & reactable)) + var/distance = max(1, get_dist(thing, epicenter)) var/fraction = 0.5 / (2 ** distance) //50/25/12/6... for a 200u splash, 25/12/6/3... for a 100u, 12/6/3/1 for a 50u - source.expose(A, TOUCH, fraction) + source.expose(thing, TOUCH, fraction)