Refactored movement observable away (#20083)

Refactored movement observable away, use only the signal.
Some tweaks to the signal.
This commit is contained in:
Fluffy
2024-10-26 15:53:07 +00:00
committed by GitHub
parent 3de4911dc8
commit d40d459d42
35 changed files with 532 additions and 434 deletions
+186
View File
@@ -0,0 +1,186 @@
/datum/component/orbiter
can_transfer = TRUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/list/orbiter_list
var/datum/movement_detector/tracker
//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
//clockwise: whether you orbit clockwise or anti clockwise
//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
/datum/component/orbiter/Initialize(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(!istype(orbiter) || !isatom(parent) || isarea(parent))
return COMPONENT_INCOMPATIBLE
orbiter_list = list()
begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/datum/component/orbiter/RegisterWithParent()
var/atom/target = parent
target.orbiters = src
if(ismovable(target))
tracker = new(target, CALLBACK(src, PROC_REF(move_react)))
// RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(orbiter_glide_size_update)) //Aurora doesn't vary glides
/datum/component/orbiter/UnregisterFromParent()
// UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE) //Aurora doesn't vary glides
var/atom/target = parent
target.orbiters = null
QDEL_NULL(tracker)
/datum/component/orbiter/Destroy()
var/atom/master = parent
if(master.orbiters == src)
master.orbiters = null
for(var/i in orbiter_list)
end_orbit(i)
orbiter_list = null
return ..()
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(!newcomp)
begin_orbit(arglist(args.Copy(3)))
return
// The following only happens on component transfers
for(var/o in newcomp.orbiter_list)
var/atom/movable/incoming_orbiter = o
incoming_orbiter.orbiting = src
// It is important to transfer the signals so we don't get locked to the new orbiter component for all time
newcomp.UnregisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED)
RegisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react))
orbiter_list += newcomp.orbiter_list
newcomp.orbiter_list = null
/datum/component/orbiter/PostTransfer()
if(!isatom(parent) || isarea(parent) || !get_turf(parent))
return COMPONENT_INCOMPATIBLE
move_react(parent)
/datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(orbiter.orbiting)
if(orbiter.orbiting == src)
orbiter.orbiting.end_orbit(orbiter, TRUE)
else
orbiter.orbiting.end_orbit(orbiter)
orbiter_list[orbiter] = TRUE
orbiter.orbiting = src
// ADD_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT)
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react))
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter)
var/matrix/initial_transform = matrix(orbiter.transform)
orbiter_list[orbiter] = initial_transform
// Head first!
if(pre_rotation)
var/matrix/M = matrix(orbiter.transform)
var/pre_rot = 90
if(!clockwise)
pre_rot = -90
M.Turn(pre_rot)
orbiter.transform = M
var/matrix/shift = matrix(orbiter.transform)
shift.Translate(0, radius)
orbiter.transform = shift
orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
//Aurora doesn't vary glides
// if(ismob(orbiter))
// var/mob/orbiter_mob = orbiter
// orbiter_mob.updating_glide_size = FALSE
if(ismovable(parent))
var/atom/movable/movable_parent = parent
orbiter.glide_size = movable_parent.glide_size
orbiter.abstract_move(get_turf(parent))
to_chat(orbiter, SPAN_NOTICE("Now orbiting [parent]."))
/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
if(!orbiter_list[orbiter])
return
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter)
orbiter.SpinAnimation(0, 0, parallel = FALSE) //TG has it with parallel = TRUE but it seems to not work here with that, for some reason
if(istype(orbiter_list[orbiter],/matrix)) //This is ugly.
orbiter.transform = orbiter_list[orbiter]
orbiter_list -= orbiter
orbiter.stop_orbit(src)
orbiter.orbiting = null
if(ismob(orbiter))
var/mob/orbiter_mob = orbiter
// orbiter_mob.updating_glide_size = TRUE //Aurora doesn't vary glides
orbiter_mob.glide_size = 8
if(isobserver(orbiter))
var/mob/abstract/observer/ghostie = orbiter //is var/mob/dead/observer/ghostie = orbiter in tg
ghostie.orbiting_ref = null
// REMOVE_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT)
if(!refreshing && !length(orbiter_list) && !QDELING(src))
qdel(src)
// This proc can receive signals by either the thing being directly orbited or anything holding it
/datum/component/orbiter/proc/move_react(atom/movable/master, atom/mover, atom/oldloc, direction)
set waitfor = FALSE // Transfer calls this directly and it doesnt care if the ghosts arent done moving
if(master.loc == oldloc)
return
var/turf/newturf = get_turf(master)
if(!newturf)
qdel(src)
var/atom/curloc = master.loc
for(var/atom/movable/movable_orbiter as anything in orbiter_list)
if(QDELETED(movable_orbiter) || movable_orbiter.loc == newturf)
continue
movable_orbiter.abstract_move(newturf)
if(CHECK_TICK && master.loc != curloc)
// We moved again during the checktick, cancel current operation
break
/datum/component/orbiter/proc/orbiter_move_react(atom/movable/orbiter, atom/oldloc, direction)
SIGNAL_HANDLER
if(orbiter.loc == get_turf(parent))
return
end_orbit(orbiter)
/datum/component/orbiter/proc/orbiter_glide_size_update(datum/source, target)
SIGNAL_HANDLER
for(var/orbiter in orbiter_list)
var/atom/movable/movable_orbiter = orbiter
movable_orbiter.glide_size = target
/////////////////////
/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE)
if(!istype(A) || !get_turf(A) || A == src)
return
// if (HAS_TRAIT(A, TRAIT_ORBITING_FORBIDDEN))
// // Stealth-mins have an empty name, don't want "You cannot orbit at this time."
// to_chat(src, SPAN_NOTICE("You cannot orbit ["[A]" || "them"] at this time."))
// return
orbit_target = A
return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/atom/movable/proc/stop_orbit(datum/component/orbiter/orbits)
orbit_target = null
return // We're just a simple hook
/atom/proc/transfer_observers_to(atom/target)
if(!orbiters || !istype(target) || !get_turf(target) || target == src)
return
target.TakeComponent(orbiters)
+55
View File
@@ -0,0 +1,55 @@
/// A datum to handle the busywork of registering signals to handle in depth tracking of a movable
/datum/movement_detector
var/atom/movable/tracked
var/datum/callback/listener
/datum/movement_detector/New(atom/movable/target, datum/callback/listener)
if(target)
track(target, listener)
/datum/movement_detector/Destroy()
untrack()
tracked = null
listener = null
return ..()
/// Sets up tracking of the given movable atom
/datum/movement_detector/proc/track(atom/movable/target, datum/callback/listener)
untrack()
tracked = target
src.listener = listener
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))
target = target.loc
/// Stops tracking
/datum/movement_detector/proc/untrack()
if(!tracked)
return
var/atom/movable/target = tracked
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
/**
* Reacts to any movement that would cause a change in coordinates of the tracked movable atom
* This works by detecting movement of either the tracked object, or anything it is inside, recursively
*/
/datum/movement_detector/proc/move_react(atom/movable/mover, atom/oldloc, direction)
SIGNAL_HANDLER
var/turf/newturf = get_turf(tracked)
if(oldloc && !isturf(oldloc))
var/atom/target = oldloc
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
if(tracked.loc != newturf)
var/atom/target = mover.loc
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react), TRUE)
target = target.loc
listener.Invoke(tracked, mover, oldloc, direction)
-11
View File
@@ -1,14 +1,3 @@
/atom/movable/proc/move_to_turf(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T && T != loc)
forceMove(T)
// Similar to above but we also follow into nullspace
/atom/movable/proc/move_to_turf_or_null(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T != loc)
forceMove(T)
/atom/movable/proc/move_to_loc_or_null(var/atom/movable/am, var/old_loc, var/new_loc)
if(new_loc != loc)
forceMove(new_loc)
-45
View File
@@ -1,45 +0,0 @@
GLOBAL_DATUM_INIT(moved_event, /singleton/observ/moved, new)
/singleton/observ/moved
name = "Moved"
expected_type = /atom/movable
/singleton/observ/moved/register(var/eventSource, var/datum/procOwner, var/proc_call)
. = ..()
var/atom/movable/child = eventSource
if(.)
var/atom/movable/parent = child.loc
while(istype(parent) && !GLOB.moved_event.is_listening(parent, child))
GLOB.moved_event.register(parent, child, TYPE_PROC_REF(/atom/movable, recursive_move))
child = parent
parent = child.loc
/singleton/observ/moved/unregister(event_source, datum/listener, proc_call)
. = ..()
var/atom/movable/child = event_source
if(.)
var/atom/movable/parent = child.loc
while(istype(parent) && GLOB.moved_event.is_listening(parent, child))
GLOB.moved_event.unregister(parent, child, TYPE_PROC_REF(/atom/movable, recursive_move))
child = parent
parent = child.loc
/singleton/observ/moved/proc/register_all_movement(var/event_source, var/listener)
GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)
/singleton/observ/moved/proc/unregister_all_movement(var/event_source, var/listener)
GLOB.moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set)
/********************
* Movement Handling *
********************/
/atom/movable/proc/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T && T != loc)
forceMove(T)
/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc)
GLOB.moved_event.raise_event(src, old_loc, new_loc)
+4 -4
View File
@@ -197,19 +197,19 @@ GLOBAL_DATUM_INIT(sound_player, /singleton/sound_player, new)
listeners += listener
GLOB.moved_event.register(listener, src, PROC_REF(PrivUpdateListenerLoc))
RegisterSignal(listener, COMSIG_MOVABLE_MOVED, PROC_REF(PrivUpdateListenerLoc))
GLOB.destroyed_event.register(listener, src, PROC_REF(PrivRemoveListener))
PrivUpdateListenerLoc(listener, FALSE)
PrivUpdateListenerLoc(listener, update_sound = FALSE)
/datum/sound_token/proc/PrivRemoveListener(atom/listener, sound/null_sound)
null_sound = null_sound || new(channel = sound.channel)
sound_to(listener, null_sound)
GLOB.moved_event.unregister(listener, src, PROC_REF(PrivUpdateListenerLoc))
UnregisterSignal(listener, COMSIG_MOVABLE_MOVED)
GLOB.destroyed_event.unregister(listener, src, PROC_REF(PrivRemoveListener))
listeners -= listener
/datum/sound_token/proc/PrivUpdateListenerLoc(atom/listener, update_sound = TRUE)
/datum/sound_token/proc/PrivUpdateListenerLoc(atom/movable/listener, atom/old_loc, dir, forced, list/old_locs, update_sound = TRUE)
var/turf/source_turf = get_turf(source)
var/turf/listener_turf = get_turf(listener)