From 2138af3a6fdeab4df785455b202fea62c2d88d78 Mon Sep 17 00:00:00 2001 From: Roxy <75404941+TealSeer@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:22:28 -0400 Subject: [PATCH] Fix duplicate signal registration with mining mob respawners (#96827) ## About The Pull Request So it's possible for a mining mob respawner to be spawned by `/datum/biome/populate_turfs`, which calls `setup()` on the respawner, and if the mob being passed is a random spawner, it'll register `COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON` on the turf to wait for that random spawner to spawn something. Since this is happening prior to atom subsystem init, that spawn won't happen until later. Once the atom subsystem starts Initializing stuff, if the mining respawner gets Initialized before the random spawner, it'll call `spawn_mob` which, if it happens to choose the same turf its on, will register `COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON` again and runtime. ## Why It's Good For The Game image ## Changelog N/A --- code/game/objects/effects/mining_mob_respawner.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/game/objects/effects/mining_mob_respawner.dm b/code/game/objects/effects/mining_mob_respawner.dm index 545241b45db..fe98fd02df0 100644 --- a/code/game/objects/effects/mining_mob_respawner.dm +++ b/code/game/objects/effects/mining_mob_respawner.dm @@ -5,6 +5,8 @@ invisibility = INVISIBILITY_ABSTRACT /// Do we check the outdoorsness of our spawn tile? var/outdoor_only = TRUE + /// Are we waiting for a mob to spawn so we can link to it? + var/registered_spawn_signal = FALSE // Spawn somewhere in an area around the spawner rather than dead on it var/respawn_range = 3 /// Min time from storm to spawn a mob @@ -38,7 +40,7 @@ filtered_mobs += path valid_mobs = filtered_mobs - if (!our_mob?.resolve()) + if (!our_mob?.resolve() && !registered_spawn_signal) make_mob() // We're just going to go ahead and assume these won't move after being spawned @@ -51,6 +53,7 @@ if (istype(initial_spawn, /obj/effect/spawner/random)) RegisterSignal(get_turf(src), COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, PROC_REF(get_spawned_mob)) + registered_spawn_signal = TRUE else register_spawn(src, initial_spawn) @@ -85,6 +88,7 @@ var/turf/spawn_turf = pick(valid_locations) // Bit roundabout but it's the only way of intercepting mob spawners RegisterSignal(spawn_turf, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, PROC_REF(get_spawned_mob)) + registered_spawn_signal = TRUE new spawn_path(spawn_turf) /// Intercept the next mob spawned on the turf, because we might have spawned an object which spawns a mob instead @@ -94,6 +98,7 @@ return UnregisterSignal(source, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON) + registered_spawn_signal = FALSE register_spawn(source, new_spawn) play_spawn_animation(new_spawn, source)