Files
Bubberstation/code/controllers/subsystem/icon_smooth.dm
SkyratBot 848c50d5ab [MIRROR] Fix very common smoothing groups runtime by deferring icon smoothing until all atom initializations are complete [MDB IGNORE] (#21229)
* Fix very common smoothing groups runtime by deferring icon smoothing until all atom initializations are complete (#75444)

## About The Pull Request
Fixes the "bad index" runtime that shows up on 80% of rounds.

![image](https://github.com/tgstation/tgstation/assets/35135081/8b8a7b6a-90b6-4c07-8e3b-47f31e4864c5)

The issue is that during dynamic maploading, the initialization of
objects is split over several ticks. However, before the initialization
is complete, an object's smoothing groups is still in its string form
(as per [the smoothing group
optimizations](https://github.com/tgstation/tgstation/pull/71989)).
Thus, code later down the line attempts to read from this string, and
errors.

It would be expensive to check all nearby neighbors every time in any
place in this code, so instead we defer icon smoothing if there are any
initializations currently in progress. Because this only happens for
dynamic loading, the stuff being loaded dynamically is usually small,
and icon smoothing already has a somewhat visible delay for shuttles,
this delay doesn't matter.

## Changelog

🆑
fix: Fixed an issue where objects on something that loaded dynamically,
like shuttles, would not be smoothed.
/🆑

* Fix very common smoothing groups runtime by deferring icon smoothing until all atom initializations are complete

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
2023-05-16 20:51:14 +01:00

79 lines
2.3 KiB
Plaintext

SUBSYSTEM_DEF(icon_smooth)
name = "Icon Smoothing"
init_order = INIT_ORDER_ICON_SMOOTHING
wait = 1
priority = FIRE_PRIORITY_SMOOTHING
flags = SS_TICKER
///Blueprints assemble an image of what pipes/manifolds/wires look like on initialization, and thus should be taken after everything's been smoothed
var/list/blueprint_queue = list()
var/list/smooth_queue = list()
var/list/deferred = list()
/datum/controller/subsystem/icon_smooth/fire()
// We do not want to smooth icons of atoms whose neighbors are not initialized yet,
// this causes runtimes.
// Icon smoothing SS runs after atoms, so this only happens for something like shuttles.
// This kind of map loading shouldn't take too long, so the delay is not a problem.
if (SSatoms.initializing_something())
return
var/list/smooth_queue_cache = smooth_queue
while(length(smooth_queue_cache))
var/atom/smoothing_atom = smooth_queue_cache[length(smooth_queue_cache)]
smooth_queue_cache.len--
if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED))
continue
if(smoothing_atom.flags_1 & INITIALIZED_1)
smoothing_atom.smooth_icon()
else
deferred += smoothing_atom
if (MC_TICK_CHECK)
return
if (!length(smooth_queue_cache))
if (deferred.len)
smooth_queue = deferred
deferred = smooth_queue_cache
else
can_fire = FALSE
/datum/controller/subsystem/icon_smooth/Initialize()
var/list/queue = smooth_queue
smooth_queue = list()
while(length(queue))
var/atom/smoothing_atom = queue[length(queue)]
queue.len--
if(QDELETED(smoothing_atom) || !(smoothing_atom.smoothing_flags & SMOOTH_QUEUED) || !smoothing_atom.z)
continue
smoothing_atom.smooth_icon()
CHECK_TICK
queue = blueprint_queue
blueprint_queue = null
for(var/atom/movable/movable_item as anything in queue)
if(!isturf(movable_item.loc))
continue
var/turf/item_loc = movable_item.loc
item_loc.add_blueprints(movable_item)
return SS_INIT_SUCCESS
/datum/controller/subsystem/icon_smooth/proc/add_to_queue(atom/thing)
if(thing.smoothing_flags & SMOOTH_QUEUED)
return
thing.smoothing_flags |= SMOOTH_QUEUED
smooth_queue += thing
if(!can_fire)
can_fire = TRUE
/datum/controller/subsystem/icon_smooth/proc/remove_from_queues(atom/thing)
thing.smoothing_flags &= ~SMOOTH_QUEUED
smooth_queue -= thing
if(blueprint_queue)
blueprint_queue -= thing
deferred -= thing