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
🆑
qol: Jetpacks should ACTUALLY feel better now
/🆑
This commit is contained in:
SmArtKar
2024-12-15 04:49:30 +01:00
committed by GitHub
parent 469f7dc14f
commit 92d224d48f
4 changed files with 44 additions and 28 deletions
@@ -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)
+16 -5
View File
@@ -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
+16 -17
View File
@@ -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
+11 -5
View File
@@ -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