From 92d224d48ff393035477a9b44ee285e70d2ca450 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sun, 15 Dec 2024 06:49:30 +0300 Subject: [PATCH] Fourth! Time's the Charm: Actually fixes jetpack race conditions this time around (#88492) ## About The Pull Request A) Queue time can be null and it'll be valid for hotstarting loops B) Pushoffs working even when you're moving feels much better C) Jetpacks were having race issues with drift handlers because those were also using comsigs which is a remnant of old code back when they were components. Handlers should fire last, post-comsigs. D) We should not be hard-blocking jetpack movement when doing final slowdown step. Like really. ## Why It's Good For The Game Jetpacks ACTUALLY don't suck this time around. ## Changelog :cl: qol: Jetpacks should ACTUALLY feel better now /:cl: --- .../subsystem/movement/newtonian_movement.dm | 2 +- code/datums/components/jetpack.dm | 21 +++++++++--- code/datums/drift_handler.dm | 33 +++++++++---------- code/modules/mob/mob_movement.dm | 16 ++++++--- 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/code/controllers/subsystem/movement/newtonian_movement.dm b/code/controllers/subsystem/movement/newtonian_movement.dm index 41db87d722b..e4143669678 100644 --- a/code/controllers/subsystem/movement/newtonian_movement.dm +++ b/code/controllers/subsystem/movement/newtonian_movement.dm @@ -39,7 +39,7 @@ MOVEMENT_SUBSYSTEM_DEF(newtonian_movement) /datum/controller/subsystem/movement/newtonian_movement/proc/fire_moveloop(datum/move_loop/loop) // Loop isn't even running right now - if(!(loop.status & MOVELOOP_STATUS_QUEUED) || isnull(loop.queued_time)) + if(!(loop.status & MOVELOOP_STATUS_QUEUED)) return // Drop the loop, process it, and if its still valid - queue it again dequeue_loop(loop) diff --git a/code/datums/components/jetpack.dm b/code/datums/components/jetpack.dm index 1a44da7eb6d..c7ff096029b 100644 --- a/code/datums/components/jetpack.dm +++ b/code/datums/components/jetpack.dm @@ -110,6 +110,7 @@ RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_react)) RegisterSignal(user, COMSIG_MOB_CLIENT_MOVE_NOGRAV, PROC_REF(on_client_move)) RegisterSignal(user, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, PROC_REF(on_pushoff)) + RegisterSignal(user, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT, PROC_REF(on_input_block)) last_stabilization_tick = world.time START_PROCESSING(SSnewtonian_movement, src) if (effect_type) @@ -164,6 +165,17 @@ var/max_drift_force = MOVE_DELAY_TO_DRIFT(user.cached_multiplicative_slowdown) user.drift_handler.stabilize_drift(user.client.intended_direction ? dir2angle(user.client.intended_direction) : null, user.client.intended_direction ? max_drift_force : 0, stabilization_force * (seconds_per_tick * 1 SECONDS)) +/datum/component/jetpack/proc/on_input_block(mob/source) + SIGNAL_HANDLER + + if (!should_trigger(source)) + return + + if (!check_on_move.Invoke(TRUE)) + return + + return DRIFT_ALLOW_INPUT + /datum/component/jetpack/proc/on_client_move(mob/source, list/move_args) SIGNAL_HANDLER @@ -179,11 +191,10 @@ var/max_drift_force = MOVE_DELAY_TO_DRIFT(source.cached_multiplicative_slowdown) var/applied_force = drift_force var/move_dir = source.client.intended_direction - // We're not moving anywhere, try to see if we can simulate pushing off a wall - if (isnull(source.drift_handler)) - var/atom/movable/backup = source.get_spacemove_backup(move_dir, FALSE) - if (backup && !(backup.dir & move_dir)) - applied_force = max_drift_force + // Try to see if we can simulate pushing off a wall + var/atom/movable/backup = source.get_spacemove_backup(move_dir, FALSE, include_floors = TRUE) + if (backup && !(backup.dir & move_dir)) + applied_force = max_drift_force // We don't want to force the loop to fire before stabilizing if we're going to, otherwise its effects will be delayed until the next tick which is jank var/force_stabilize = FALSE diff --git a/code/datums/drift_handler.dm b/code/datums/drift_handler.dm index dc47f28819b..dcf0771d8a5 100644 --- a/code/datums/drift_handler.dm +++ b/code/datums/drift_handler.dm @@ -36,7 +36,6 @@ RegisterSignal(drifting_loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(before_move)) RegisterSignal(drifting_loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(after_move)) RegisterSignal(drifting_loop, COMSIG_QDELETING, PROC_REF(loop_death)) - RegisterSignal(parent, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, PROC_REF(attempt_halt)) if(drifting_loop.status & MOVELOOP_STATUS_RUNNING) drifting_start(drifting_loop) // There's a good chance it'll autostart, gotta catch that @@ -208,28 +207,28 @@ if(world.time < block_inputs_until) return COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE -/datum/drift_handler/proc/attempt_halt(mob/source, movement_dir, continuous_move, atom/backup) - SIGNAL_HANDLER - - if ((backup.density || !backup.CanPass(source, get_dir(backup, source))) && (get_dir(source, backup) == movement_dir || source.loc == backup.loc)) +/datum/drift_handler/proc/attempt_halt(movement_dir, continuous_move, atom/backup) + if ((backup.density || !backup.CanPass(parent, get_dir(backup, parent))) && (get_dir(parent, backup) == movement_dir || parent.loc == backup.loc)) if (drift_force >= INERTIA_FORCE_THROW_FLOOR) - source.throw_at(backup, 1, floor(1 + (drift_force - INERTIA_FORCE_THROW_FLOOR) / INERTIA_FORCE_PER_THROW_FORCE), spin = FALSE) - return + parent.throw_at(backup, 1, floor(1 + (drift_force - INERTIA_FORCE_THROW_FLOOR) / INERTIA_FORCE_PER_THROW_FORCE), spin = FALSE) + return FALSE if (drift_force < INERTIA_FORCE_SPACEMOVE_GRAB || isnull(drifting_loop)) - return + return FALSE - if (!isnull(source.client) && source.client.intended_direction) - if ((source.client.intended_direction & movement_dir) && !(get_dir(source, backup) & movement_dir)) - return + if (ismob(parent)) + var/mob/source_user = parent + if (!isnull(source_user.client) && source_user.client.intended_direction) + if ((source_user.client.intended_direction & movement_dir) && !(get_dir(source_user, backup) & movement_dir)) + return FALSE - if (drift_force <= INERTIA_FORCE_SPACEMOVE_REDUCTION / source.inertia_force_weight) - glide_to_halt(get_loop_delay(source)) - return COMPONENT_PREVENT_SPACEMOVE_HALT + if (drift_force <= INERTIA_FORCE_SPACEMOVE_REDUCTION / parent.inertia_force_weight) + glide_to_halt(get_loop_delay(parent)) + return TRUE - drift_force -= INERTIA_FORCE_SPACEMOVE_REDUCTION / source.inertia_force_weight - drifting_loop.set_delay(get_loop_delay(source)) - return COMPONENT_PREVENT_SPACEMOVE_HALT + drift_force -= INERTIA_FORCE_SPACEMOVE_REDUCTION / parent.inertia_force_weight + drifting_loop.set_delay(get_loop_delay(parent)) + return TRUE /datum/drift_handler/proc/get_loop_delay(atom/movable/movable) return (DEFAULT_INERTIA_SPEED / ((1 - INERTIA_SPEED_COEF) + drift_force * INERTIA_SPEED_COEF)) * movable.inertia_move_multiplier diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index f19a3991ca3..743bdad8c45 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -281,6 +281,9 @@ if (SEND_SIGNAL(src, COMSIG_MOB_ATTEMPT_HALT_SPACEMOVE, movement_dir, continuous_move, backup) & COMPONENT_PREVENT_SPACEMOVE_HALT) return FALSE + if (drift_handler?.attempt_halt(movement_dir, continuous_move, backup)) + return FALSE + if(continuous_move || !istype(backup) || !movement_dir || backup.anchored) return TRUE @@ -300,8 +303,9 @@ /** * Finds a target near a mob that is viable for pushing off when moving. * Takes the intended movement direction as input, alongside if the context is checking if we're allowed to continue drifting + * If include_floors is TRUE, includes floors *with gravity* */ -/mob/get_spacemove_backup(moving_direction, continuous_move) +/mob/get_spacemove_backup(moving_direction, continuous_move, include_floors = FALSE) var/atom/secondary_backup var/list/priority_dirs = (moving_direction in GLOB.cardinals) ? GLOB.cardinals : GLOB.diagonals for(var/atom/pushover as anything in range(1, get_turf(src))) @@ -309,13 +313,15 @@ continue if(isarea(pushover)) continue + var/is_priority = pushover.loc == loc || (get_dir(src, pushover) in priority_dirs) if(isturf(pushover)) var/turf/turf = pushover if(isspaceturf(turf)) continue if(!turf.density && !mob_negates_gravity()) - continue - if (get_dir(src, pushover) in priority_dirs) + if (!include_floors || !turf.has_gravity()) + continue + if (is_priority) return pushover secondary_backup = pushover continue @@ -343,13 +349,13 @@ if(moving_direction == get_dir(src, pushover)) // Can't push "off" of something that you're walking into continue if(rebound.anchored) - if (get_dir(src, rebound) in priority_dirs) + if (is_priority) return rebound secondary_backup = rebound continue if(pulling == rebound) continue - if (get_dir(src, rebound) in priority_dirs) + if (is_priority) return rebound secondary_backup = rebound return secondary_backup