From 9e39f50248f4401f2c3d6d8ecfb9741e1117a975 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:12:34 -0700 Subject: [PATCH] [MIRROR] fix some remote view component desyncs and crashes (#11814) Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> --- code/__defines/is_helpers.dm | 2 ++ code/datums/components/remote_view.dm | 10 ++++++++-- code/game/atoms_movable.dm | 3 +++ code/game/objects/items/weapons/material/kitchen.dm | 5 ++++- code/game/objects/mail.dm | 5 ++++- code/game/objects/structures/watercloset.dm | 5 ++++- code/modules/admin/verbs/adminjump.dm | 9 +++++++++ code/modules/fishing/fishing_net.dm | 5 ++++- code/modules/food/food.dm | 5 ++++- code/modules/mob/inventory.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/mob/living/silicon/pai/pai.dm | 2 +- .../subtypes/animal/alien animals/stardog.dm | 1 + code/modules/mob/mob.dm | 4 ++++ code/modules/overmap/ships/computers/helm.dm | 4 +++- code/modules/overmap/ships/computers/sensors.dm | 4 +++- code/modules/tgui/modules/ntos-only/uav.dm | 4 +++- code/modules/tgui/modules/overmap.dm | 8 ++++++-- 18 files changed, 65 insertions(+), 15 deletions(-) diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index a90802f642..4a1fedcdce 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -35,6 +35,8 @@ GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur"))) #define isstructure(A) istype(A, /obj/structure) +#define isdisposalpacket(A) istype(A,/obj/structure/disposalholder) + //--------------- //#define isarea(D) istype(D, /area) //Built in diff --git a/code/datums/components/remote_view.dm b/code/datums/components/remote_view.dm index dbb8cd4455..00376ecb91 100644 --- a/code/datums/components/remote_view.dm +++ b/code/datums/components/remote_view.dm @@ -191,8 +191,9 @@ host_mob.toggle_zoom_hud() host_item.zoom = FALSE // return view offset - host_mob.client.pixel_x = 0 - host_mob.client.pixel_y = 0 + if(host_mob.client) + host_mob.client.pixel_x = 0 + host_mob.client.pixel_y = 0 host_mob.handle_vision() // decouple UnregisterSignal(host_item, COMSIG_QDELETING) @@ -257,6 +258,9 @@ view_coordinator.look(host_mob) LAZYDISTINCTADD(viewers, WEAKREF(host_mob)) RegisterSignal(view_coordinator, COMSIG_REMOTE_VIEW_CLEAR, PROC_REF(handle_endview)) + // If you get this crash, it's because check_eye() in look() failed + if(!parent) + CRASH("Remoteview failed, look() cancelled view during component Initilize. Usually this is caused by check_eye().") /datum/component/remote_view/viewer_managed/Destroy(force) UnregisterSignal(view_coordinator, COMSIG_REMOTE_VIEW_CLEAR) @@ -298,6 +302,8 @@ if(!host_mob) return if(isturf(host_mob.loc)) + if(oldloc == remote_view_target) + needs_to_decouple = TRUE decouple_view_to_turf( host_mob, host_mob.loc) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 3cf5b8023e..e859880c03 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -753,6 +753,9 @@ return if(QDELETED(src)) return + if(ismob(src)) // incase there was a client inside an object being yoinked + var/mob/M = src + M.reset_perspective(src) // Force reset to self before teleport forceMove(get_turf(usr)) if(href_list[VV_HK_EDIT_PARTICLES] && check_rights(R_VAREDIT)) diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index f6b166fd5f..02164adfa9 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -132,7 +132,10 @@ /obj/item/material/kitchen/utensil/container_resist(mob/living/M) if(food_inserted_micros) food_inserted_micros -= M - M.forceMove(get_turf(src)) + if(isdisposalpacket(loc)) + M.forceMove(loc) + else + M.forceMove(get_turf(src)) to_chat(M, span_warning("You climb off of \the [src].")) /obj/item/material/kitchen/utensil/fork diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index 5331dce999..47d9cbab86 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -51,7 +51,10 @@ /obj/item/mail/container_resist(mob/living/M) if(istype(M, /mob/living/voice)) return - M.forceMove(get_turf(src)) + if(isdisposalpacket(loc)) + M.forceMove(loc) + else + M.forceMove(get_turf(src)) to_chat(M, span_warning("You climb out of \the [src].")) /obj/item/mail/envelope diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index cb714ddafb..808b53cb4a 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -399,7 +399,10 @@ return /obj/item/bikehorn/rubberducky/pink/container_resist(var/mob/living/escapee) - escapee.forceMove(get_turf(src)) + if(isdisposalpacket(loc)) + escapee.forceMove(loc) + else + escapee.forceMove(get_turf(src)) to_chat(escapee, span_vnotice("You managed to crawl out of the rubber ducky!")) /obj/item/bikehorn/rubberducky/grey diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index b6dfcb6187..3794fde11c 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -26,6 +26,7 @@ return usr.on_mob_jump() + usr.reset_perspective(usr) usr.forceMove(pick(get_area_turfs(A))) log_admin("[key_name(usr)] jumped to [A]") message_admins("[key_name_admin(usr)] jumped to [A]", 1) @@ -40,6 +41,7 @@ log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]") message_admins("[key_name_admin(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]", 1) usr.on_mob_jump() + usr.reset_perspective(usr) usr.forceMove(T) feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! else @@ -72,6 +74,7 @@ var/turf/T = get_turf(M) if(isturf(T)) A.on_mob_jump() + A.reset_perspective(A) A.forceMove(T) log_admin("[key_name(usr)] jumped to [key_name(M)]") message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]", 1) @@ -94,6 +97,7 @@ if(!T) to_chat(usr, span_warning("Those coordinates are outside the boundaries of the map.")) return + A.reset_perspective(A) A.forceMove(T) feedback_add_details("admin_verb","JC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]") @@ -119,6 +123,7 @@ log_admin("[key_name(usr)] jumped to [key_name(M)]") message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]", 1) usr.on_mob_jump() + usr.reset_perspective(usr) usr.forceMove(get_turf(M)) feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! else @@ -142,6 +147,7 @@ message_admins(msg) admin_ticket_log(M, msg) M.on_mob_jump() + M.reset_perspective(M) M.forceMove(get_turf(usr)) feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! else @@ -172,6 +178,7 @@ admin_ticket_log(M, msg) if(M) M.on_mob_jump() + M.reset_perspective(M) // Force reset to self before teleport M.forceMove(get_turf(usr)) feedback_add_details("admin_verb","GK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! else @@ -191,6 +198,7 @@ if(!M) return M.on_mob_jump() + M.reset_perspective(M) // Force reset to self before teleport M.forceMove(pick(get_area_turfs(A))) feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -225,6 +233,7 @@ if(ismob(AM)) var/mob/M = AM M.on_mob_jump() + M.reset_perspective(M) // Force reset to self before teleport AM.forceMove(T) feedback_add_details("admin_verb", "MA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! message_admins("[key_name_admin(usr)] jumped [AM] to coordinates [tx], [ty], [tz]") diff --git a/code/modules/fishing/fishing_net.dm b/code/modules/fishing/fishing_net.dm index 7a107be913..b34dfc352f 100644 --- a/code/modules/fishing/fishing_net.dm +++ b/code/modules/fishing/fishing_net.dm @@ -186,7 +186,10 @@ /obj/item/material/fishing_net/butterfly_net/container_resist(mob/living/M) if(prob(20)) - M.forceMove(get_turf(src)) + if(isdisposalpacket(loc)) + M.forceMove(loc) + else + M.forceMove(get_turf(src)) to_chat(M, span_warning("You climb out of \the [src].")) update_icon() update_weight() diff --git a/code/modules/food/food.dm b/code/modules/food/food.dm index 645da3969a..54c2ec281f 100644 --- a/code/modules/food/food.dm +++ b/code/modules/food/food.dm @@ -63,7 +63,10 @@ if(istype(M, /mob/living/voice)) return // CHOMPAdd - Stops sentient food from astral projecting if(food_inserted_micros) food_inserted_micros -= M - M.forceMove(get_turf(src)) + if(isdisposalpacket(loc)) + M.forceMove(loc) + else + M.forceMove(get_turf(src)) to_chat(M, span_warning("You climb out of \the [src].")) #undef CELLS diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 7f1883975f..09e658122b 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -157,7 +157,7 @@ var/list/slot_equipment_priority = list( \ /mob/proc/drop_from_inventory(var/obj/item/W, var/atom/target) if(!W) return FALSE - if(isnull(target) && istype( src.loc,/obj/structure/disposalholder)) + if(isnull(target) && isdisposalpacket(src.loc)) return remove_from_mob(W, src.loc) return remove_from_mob(W, target) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c78e207e60..2d47195c1e 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1554,7 +1554,7 @@ /mob/living/carbon/human/drop_from_inventory(var/obj/item/W, var/atom/target = null) if(W in organs) return FALSE - if(isnull(target) && istype( src.loc,/obj/structure/disposalholder)) + if(isnull(target) && isdisposalpacket(src.loc)) return remove_from_mob(W, src.loc) return ..() diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 77c87e8211..3f9c3b94b1 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -426,7 +426,7 @@ src.forceMove(card) card.forceMove(B) - if(istype(loc,/obj/structure/disposalholder)) + if(isdisposalpacket(loc)) var/obj/structure/disposalholder/hold = loc src.forceMove(card) card.forceMove(hold) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm index 348a5e3227..7728d32a35 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm @@ -1315,6 +1315,7 @@ return L.stop_pulling() L.Weaken(3) + L.reset_perspective() // Needed for food items that get gobbled with micros in them GLOB.prey_eaten_roundstat++ if(target.reciever) //We don't have to worry AM.unbuckle_all_mobs(TRUE) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 8e9b65ea05..cf20aa2fef 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -254,6 +254,8 @@ SHOULD_CALL_PARENT(TRUE) if(!client) return + if(!isnull(new_eye) && QDELETED(new_eye)) + new_eye = src // Something has gone terribly wrong if(new_eye) if(ismovable(new_eye)) @@ -296,6 +298,8 @@ return FALSE if(isturf(loc)) // Cannot be remote if it was a turf, also obj and turf flags overlap so stepping into space triggers remoteview endlessly. return FALSE + if(QDELETED(loc)) + return FALSE // Check if we actually need to drop our current remote view component, as this is expensive to do, and leads to more difficult to understand error prone logic var/datum/component/remote_view/remote_comp = GetComponent(/datum/component/remote_view) if(remote_comp?.looking_at_target_already(loc)) diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm index 8914dd3d74..be6586e071 100644 --- a/code/modules/overmap/ships/computers/helm.dm +++ b/code/modules/overmap/ships/computers/helm.dm @@ -270,7 +270,9 @@ GLOBAL_LIST_EMPTY(all_waypoints) . = TRUE if("manual") - if(!viewing_overmap(ui.user) && linked) + if(check_eye(ui.user) < 0) + return FALSE + else if(!viewing_overmap(ui.user) && linked) if(!viewers) viewers = list() // List must exist for pass by reference to work start_coordinated_remoteview(ui.user, linked, viewers) else diff --git a/code/modules/overmap/ships/computers/sensors.dm b/code/modules/overmap/ships/computers/sensors.dm index 93f7af14af..3632df5036 100644 --- a/code/modules/overmap/ships/computers/sensors.dm +++ b/code/modules/overmap/ships/computers/sensors.dm @@ -89,7 +89,9 @@ switch(action) if("viewing") if(ui.user && !isAI(ui.user)) - if(!viewing_overmap(ui.user) && linked) + if(check_eye(ui.user) < 0) + . = FALSE + else if(!viewing_overmap(ui.user) && linked) if(!viewers) viewers = list() // List must exist for pass by reference to work start_coordinated_remoteview(ui.user, linked, viewers) else diff --git a/code/modules/tgui/modules/ntos-only/uav.dm b/code/modules/tgui/modules/ntos-only/uav.dm index 04ab27ed17..d1c1b8533d 100644 --- a/code/modules/tgui/modules/ntos-only/uav.dm +++ b/code/modules/tgui/modules/ntos-only/uav.dm @@ -73,7 +73,9 @@ if(current_uav.check_eye(ui.user) < 0) to_chat(ui.user,span_warning("The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.")) else - if(!viewing_uav(ui.user)) + if(check_eye(ui.user) < 0) + return FALSE + else if(!viewing_uav(ui.user)) if(!viewers) viewers = list() // List must exist for pass by reference to work start_coordinated_remoteview(ui.user, current_uav, viewers) else diff --git a/code/modules/tgui/modules/overmap.dm b/code/modules/tgui/modules/overmap.dm index 5854c00ff3..8bc7b82f06 100644 --- a/code/modules/tgui/modules/overmap.dm +++ b/code/modules/tgui/modules/overmap.dm @@ -136,7 +136,9 @@ return FALSE if(action == "viewing") - if(!viewing_overmap(ui.user)) + if(check_eye(ui.user) < 0) + return FALSE + else if(!viewing_overmap(ui.user)) if(!viewers) viewers = list() // List must exist for pass by reference to work start_coordinated_remoteview(ui.user, linked, viewers) else @@ -400,7 +402,9 @@ . = TRUE if("manual") - if(!viewing_overmap(ui.user)) + if(check_eye(ui.user) < 0) + return FALSE + else if(!viewing_overmap(ui.user)) if(!viewers) viewers = list() start_coordinated_remoteview(ui.user, linked, viewers) else