From 546dc7fdfa03de0f81e12881086191db5f0f3add Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Fri, 20 Feb 2026 17:58:39 -0800 Subject: [PATCH] Quarters camera chunk area, Implements better yielding to subsystem on update. (#94530) ## About The Pull Request [cameras should actually show all of their view](https://github.com/tgstation/tgstation/commit/a8ef0f3bd7f16e590b9fae193f645c6cb6255f8f) Melb fucked up luminosity a bit (cries) [Implements camera range as the deciding factor for who can see a chunk](https://github.com/tgstation/tgstation/commit/bf4f9776dfce1c15e756ae1933a96ff0cff2dbf0) This allows us to safely modify chunk size (which I do, down to 8, which increases the actual cost involved in doing a full z update, but decreases the cost per chunk significantly) I use the range to macro optimize chunk New, we can safely use a bounding box instead of multiple urange calls and get about 1/3 the performance hit, even with a lower range (and thus 4x as many chunks) Standard caching and such applies [Fixes cameras not looking down correctly](https://github.com/tgstation/tgstation/commit/99b23f25203f34f04c0f92bb7d191699b91a439a) [Implements yielding support for individual chunks](https://github.com/tgstation/tgstation/commit/bdd2d01106465b8498307c16f83e9dd90706652a) This should functionally remove lagspikes from the cameras subsystem, which just leaves the problem of ais flying around. Much better tick obedience: https://github.com/user-attachments/assets/607d61a4-ad96-450c-acdf-10da967ab49b I tested this pr with #94522 to confirm that halving chunk sizes would have a benefit, see below: image image image image Things to note: Mean cost of finding turfs goes from 2ms to 1ms Max cost of finding turfs goes down by somewhere between 30% and 50%. I'd call this worthwhile, even if total cost of updating has gone up slightly. [Properly manages the camera refs in chunks](https://github.com/tgstation/tgstation/pull/94530/commits/00c97183ca83a91d95b9afcde70814c36a8f9a5e) [00c9718](https://github.com/tgstation/tgstation/pull/94530/commits/00c97183ca83a91d95b9afcde70814c36a8f9a5e) Turns out our solution for moving cameras in chunk code was to just... NOT CARE!! This means any moving camera is going to cause hard deletes. This was an issue during unit tests because of a stripping unit test. I suspect it only showed up here because I reduced the chunk size so we actually enter/leave a new set of chunks. I fixed this by reworking things to use a "leaving/joining" pattern. There's some other stuff here, mostly cleaning up old copypasta'd cruft in the code adjacent to moving cameras. I also changed the cameras and processing cameras alists back into lists, mostly for the sake of vv ability this didn't actually break anything. The harddel wasn't showing up because it was a number keyed alist, and reference tracking isn't built to find those (yet, pr up) ## Why It's Good For The Game I want AIs flying around to not cause massive lag spikes. That + the camera subsystem are one of like 4 things that's causing reliable tidi on live and it makes me upset. ## Changelog :cl: fix: Cameras should work a little better (won't fail in the dark, will display multiz correctly refactor: Changed how static turf generation thinks about cameras. Shouldn't break anything but it MIGHT so keep an eye out for that. The chunks we use to divvy up the world for them are also 1/4th the area now, which should make flying around as ai less lagsikey /:cl: --------- Co-authored-by: Lucy --- code/__DEFINES/cameranets.dm | 7 +- code/__HELPERS/spatial_info.dm | 2 +- code/controllers/subsystem/cameras.dm | 80 ++++++++--- code/datums/components/simple_bodycam.dm | 12 +- code/game/machinery/camera/camera.dm | 13 +- .../mob/living/silicon/ai/freelook/chunk.dm | 135 ++++++++++++++---- code/modules/mob/living/silicon/silicon.dm | 1 - .../mob/living/silicon/silicon_movement.dm | 25 +--- .../file_system/programs/secureye.dm | 2 +- code/modules/vehicles/mecha/_mecha.dm | 2 - code/modules/vehicles/mecha/mecha_movement.dm | 27 +--- .../wiremod/components/atom/remotecam.dm | 4 +- 12 files changed, 202 insertions(+), 108 deletions(-) diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm index 75cdb072ea9..9889dbd7535 100644 --- a/code/__DEFINES/cameranets.dm +++ b/code/__DEFINES/cameranets.dm @@ -1,7 +1,10 @@ +// Needs to be constant because we need to know how many turfs out to update chunks from our source +#define MAX_CAMERA_RANGE 7 + /// We only want chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc.. -#define CHUNK_SIZE 16 +#define CHUNK_SIZE 8 /// Takes a position, transforms it into a chunk bounded position. Indexes at 1 so it'll land on actual turfs always -#define GET_CHUNK_COORD(v) (max((FLOOR(v, CHUNK_SIZE)), 1)) +#define GET_CHUNK_COORD(v) max((FLOOR((v), CHUNK_SIZE)), 1) //List of different camera nets, cameras are given this in the map and camera consoles can only view them if //they share this network with them. diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index 1135c93b055..424cd26348b 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -406,7 +406,7 @@ /// get_hear that only gets turfs so we can use as_anything /proc/get_hear_turfs(range, atom/source) var/lum = source.luminosity - source.luminosity = 6 + source.luminosity = range + 2 . = list() for(var/turf/turf in view(range, source)) . += turf diff --git a/code/controllers/subsystem/cameras.dm b/code/controllers/subsystem/cameras.dm index 5f5e9a2ec1b..62e8af1c973 100644 --- a/code/controllers/subsystem/cameras.dm +++ b/code/controllers/subsystem/cameras.dm @@ -38,8 +38,8 @@ SUBSYSTEM_DEF(cameras) var/list/current_run = src.current_run while(current_run.len) var/datum/camerachunk/chunk = current_run[current_run.len] - chunk.force_update(only_if_necessary = TRUE) // Forces an update if necessary - current_run.len-- + if(chunk.yield_update()) + current_run.len-- if(MC_TICK_CHECK) break @@ -131,13 +131,55 @@ SUBSYSTEM_DEF(cameras) major_chunk_change(new_cam, ADD_CAMERA) /** - * Used for Cyborg/mecha cameras. Since portable cameras can be in ANY chunk. - * update_delay_buffer is passed all the way to queue_update() from their camera updates on movement - * to change the time between static updates. + * Used to update cameras that are movin, since most everything in the game can. + * update_delay_buffer is passed to allow variable update delays. useful so one + * camera'd guy moving doesn't absolutely spam updates to watching ais (laggin the server) */ -/datum/controller/subsystem/cameras/proc/update_portable_camera(obj/machinery/camera/updating_camera, update_delay_buffer) - if(updating_camera.can_use()) - major_chunk_change(updating_camera, ADD_CAMERA, update_delay_buffer) +/datum/controller/subsystem/cameras/proc/camera_moved(obj/machinery/camera/updating_camera, turf/old_turf, turf/new_turf, update_delay_buffer) + if(old_turf == new_turf) + return + + var/list/old_chunks = list() + var/range_difference = MAX_CAMERA_RANGE + 1 + if(!isnull(old_turf)) + var/x1 = max(1, old_turf.x - range_difference) + var/y1 = max(1, old_turf.y - range_difference) + var/x2 = min(world.maxx, old_turf.x + range_difference) + var/y2 = min(world.maxy, old_turf.y + range_difference) + for(var/x = x1; x <= x2; x += CHUNK_SIZE) + for(var/y = y1; y <= y2; y += CHUNK_SIZE) + var/datum/camerachunk/chunk = get_camera_chunk(x, y, old_turf.z) + if(isnull(chunk)) + continue + old_chunks += chunk + // if we've moved, what we can see will have changed so queue er up + chunk.queue_update(updating_camera, update_delay_buffer) + + var/list/new_chunks = list() + if(!isnull(new_turf) && updating_camera.can_use()) + if(QDELETED(updating_camera)) + stack_trace("Tried to add a qdeleting camera to the net") + else + var/x1 = max(1, new_turf.x - range_difference) + var/y1 = max(1, new_turf.y - range_difference) + var/x2 = min(world.maxx, new_turf.x + range_difference) + var/y2 = min(world.maxy, new_turf.y + range_difference) + for(var/x = x1; x <= x2; x += CHUNK_SIZE) + for(var/y = y1; y <= y2; y += CHUNK_SIZE) + var/datum/camerachunk/chunk = get_camera_chunk(x, y, new_turf.z) + if(isnull(chunk)) + continue + new_chunks += chunk + // if we've moved, what we can see will have changed so queue er up + chunk.queue_update(updating_camera, update_delay_buffer) + + // First, cut us from chunks who we can't see anymore + for(var/datum/camerachunk/lost as anything in old_chunks - new_chunks) + lost.cameras["[old_turf.z]"] -= updating_camera + + // Then we add to turfs who we can newly see! + for(var/datum/camerachunk/found as anything in new_chunks - old_chunks) + found.cameras["[new_turf.z]"] |= updating_camera /** * Never access this proc directly!!!! @@ -158,10 +200,11 @@ SUBSYSTEM_DEF(cameras) if(isnull(chunk_turf)) return - var/x1 = max(1, chunk_turf.x - (CHUNK_SIZE / 2)) - var/y1 = max(1, chunk_turf.y - (CHUNK_SIZE / 2)) - var/x2 = min(world.maxx, chunk_turf.x + (CHUNK_SIZE / 2)) - var/y2 = min(world.maxy, chunk_turf.y + (CHUNK_SIZE / 2)) + var/range_difference = MAX_CAMERA_RANGE + 1 + var/x1 = max(1, chunk_turf.x - range_difference) + var/y1 = max(1, chunk_turf.y - range_difference) + var/x2 = min(world.maxx, chunk_turf.x + range_difference) + var/y2 = min(world.maxy, chunk_turf.y + range_difference) for(var/x = x1; x <= x2; x += CHUNK_SIZE) for(var/y = y1; y <= y2; y += CHUNK_SIZE) var/datum/camerachunk/chunk = get_camera_chunk(x, y, chunk_turf.z) @@ -169,19 +212,20 @@ SUBSYSTEM_DEF(cameras) continue if(choice == REMOVE_CAMERA) // Remove the camera. - chunk.cameras[chunk_turf.z] -= center_or_camera + chunk.cameras["[chunk_turf.z]"] -= center_or_camera if(choice == ADD_CAMERA) // You can't have the same camera in the list twice. - chunk.cameras[chunk_turf.z] |= center_or_camera + chunk.cameras["[chunk_turf.z]"] |= center_or_camera chunk.queue_update(center_or_camera, update_delay_buffer) /// A faster, turf only version of [/datum/controller/subsystem/cameras/proc/major_chunk_change] /// For use in sensitive code, be careful with it /datum/controller/subsystem/cameras/proc/bare_major_chunk_change(turf/changed) - var/x1 = max(1, changed.x - (CHUNK_SIZE / 2)) - var/y1 = max(1, changed.y - (CHUNK_SIZE / 2)) - var/x2 = min(world.maxx, changed.x + (CHUNK_SIZE / 2)) - var/y2 = min(world.maxy, changed.y + (CHUNK_SIZE / 2)) + var/range_difference = MAX_CAMERA_RANGE + 1 + var/x1 = max(1, changed.x - range_difference) + var/y1 = max(1, changed.y - range_difference) + var/x2 = min(world.maxx, changed.x + range_difference) + var/y2 = min(world.maxy, changed.y + range_difference) for(var/x = x1; x <= x2; x += CHUNK_SIZE) for(var/y = y1; y <= y2; y += CHUNK_SIZE) var/datum/camerachunk/chunk = get_camera_chunk(x, y, changed.z) diff --git a/code/datums/components/simple_bodycam.dm b/code/datums/components/simple_bodycam.dm index 1723a7a0a5a..f4c54ee22ee 100644 --- a/code/datums/components/simple_bodycam.dm +++ b/code/datums/components/simple_bodycam.dm @@ -29,7 +29,7 @@ RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(rotate_cam)) RegisterSignals(bodycam, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED), PROC_REF(camera_gone)) - do_update_cam() + do_update_cam(null) /datum/component/simple_bodycam/Destroy() if(QDELETED(bodycam)) @@ -51,12 +51,12 @@ /datum/component/simple_bodycam/proc/update_cam(datum/source, atom/old_loc, ...) SIGNAL_HANDLER + do_update_cam(old_loc) - if(get_turf(old_loc) != get_turf(parent)) - do_update_cam() - -/datum/component/simple_bodycam/proc/do_update_cam() - SScameras.update_portable_camera(bodycam, camera_update_time) +/datum/component/simple_bodycam/proc/do_update_cam(atom/old_loc) + if(!bodycam?.can_use()) + return + SScameras.camera_moved(bodycam, get_turf(old_loc), get_turf(bodycam), camera_update_time) /datum/component/simple_bodycam/proc/rotate_cam(datum/source, old_dir, new_dir) SIGNAL_HANDLER diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 38bdd0e2f00..3b6e40c0d34 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -144,7 +144,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) /obj/machinery/camera/Destroy(force) if(can_use()) toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks - SScameras.remove_camera_from_chunk(src) SScameras.cameras -= src cancelCameraAlarm() if(isarea(myarea)) @@ -154,6 +153,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) QDEL_NULL(xray_module) QDEL_NULL(emp_module) QDEL_NULL(proximity_monitor) + // moveToNullspace will clear us from our current chunks return ..() /obj/machinery/camera/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) @@ -180,6 +180,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) emp_module = null removeMotion() +/obj/machinery/camera/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + SScameras.camera_moved(src, get_turf(old_loc), get_turf(loc)) + /obj/machinery/camera/proc/create_prox_monitor() if(!proximity_monitor) proximity_monitor = new(src, 1) @@ -271,6 +275,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) user.switchCamera(src) /obj/machinery/camera/proc/setViewRange(num = 7) + if(num > MAX_CAMERA_RANGE) + CRASH("Attempted to set camera view range to something ([num]) greater then we support ([MAX_CAMERA_RANGE]).\ + This would break chunk updating. If you really need to do this, update MAX_CAMERA_RANGE") src.view_range = num SScameras.update_visibility(src) @@ -424,10 +431,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) // Haha datum var access KILL ME for(var/turf/seen as anything in see) if(check_lower) - var/turf/below = GET_TURF_BELOW(seen) + var/turf/below = seen while(below && istransparentturf(below)) - see += RANGE_TURFS(1, below) below = GET_TURF_BELOW(below) + see += RANGE_TURFS(1, below) if(check_higher) var/turf/above = GET_TURF_ABOVE(seen) while(above && istransparentturf(above)) diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm index 5a9c093a31b..04281f0b762 100644 --- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm +++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm @@ -9,8 +9,9 @@ ///turfs our cameras can see inside our grid var/list/visibleTurfs = list() ///cameras that can see into our grid - ///indexed by the z level of the camera - var/alist/cameras = alist() + ///indexed by the string z level of the camera + ///this could one day be an alist but vv doesn't work with it yet + var/list/list/cameras = list() ///list of all turfs, associative with that turf's static image ///turf -> /image var/list/turfs = list() @@ -26,6 +27,12 @@ /// List of atoms that caused the chunk to update - assoc atom ref() to opacity on queue var/list/update_sources = list() + /// Are we currently being updated by the cameras subsystem? + var/currently_updating = FALSE + /// List of cameras that need to be processed. For use in yielding when being lazyupdated by the cameras subsystem + var/list/list/processing_cameras = list() + /// List of newly visible turfs that are currently being generated. For use in lazyupdating. + var/list/processing_visible_turfs = list() /// Add a camera eye to the chunk, updating the chunk if necessary. /datum/camerachunk/proc/add(mob/eye/camera/eye) @@ -58,6 +65,7 @@ addtimer(CALLBACK(src, PROC_REF(update)), update_delay_buffer || 1, TIMER_UNIQUE) return + reset_update() // Only start queue if this is the first thing to queue an update var/start_queue = !length(update_sources) @@ -76,6 +84,7 @@ // So we can safely remove this atom as a "source of update" else if(update_sources[update_key] != update_source.opacity) update_sources -= update_key + _dequeue_update() return if(!start_queue) @@ -91,7 +100,15 @@ // Something forced an update during the delay if(!length(update_sources)) return - SScameras.chunks_to_update[src] += 1 + SScameras.chunks_to_update[src] = TRUE + +/datum/camerachunk/proc/_dequeue_update() + PRIVATE_PROC(TRUE) + // Whelp + if(length(update_sources)) + return + SScameras.chunks_to_update -= src + SScameras.current_run -= src /** * Forces the chunk to update immediately @@ -103,28 +120,84 @@ return update() -/// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists. +/// Reset any in progress update +/datum/camerachunk/proc/reset_update() + if(!currently_updating) + return + + processing_visible_turfs = list() + processing_cameras = list() + currently_updating = FALSE + // Not allowed to stick around in the list forever, that'd be dumb + SScameras.current_run -= src + _queue_update() + +/// Updates our chunk in a lazy fashion, so large amounts of cameras don't lead to overtime spikes +/// Returns FALSE if the update is unfinished, TRUE if it's complete +/datum/camerachunk/proc/yield_update() + if(SScameras.disable_camera_updates) + return TRUE + + if(!currently_updating) + currently_updating = TRUE + processing_cameras = list() + for(var/z_level in lower_z to upper_z) + processing_cameras["[z_level]"] = cameras["[z_level]"].Copy() + + var/list/updated_visible_turfs = src.processing_visible_turfs + for(var/z_level in lower_z to upper_z) + var/list/processing = processing_cameras["[z_level]"] + while(length(processing)) + var/obj/machinery/camera/current_camera = processing[length(processing)] + processing.len-- + if(!current_camera?.can_use()) + if(TICK_CHECK) + return FALSE + continue + + var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), z_level) + if(get_dist(point, current_camera) > MAX_CAMERA_RANGE + (CHUNK_SIZE / 2)) + continue + + for(var/turf/vis_turf as anything in current_camera.can_see() & turfs) + updated_visible_turfs[vis_turf] = vis_turf + + if(TICK_CHECK) + return FALSE + + update_with_turfs(updated_visible_turfs) + update_sources.Cut() + reset_update() + return TRUE + +/// Perfroms a full update of the chunk /datum/camerachunk/proc/update() if(SScameras.disable_camera_updates) return update_sources.Cut() + _dequeue_update() + reset_update() var/list/updated_visible_turfs = list() for(var/z_level in lower_z to upper_z) - for(var/obj/machinery/camera/current_camera as anything in cameras[z_level]) - if(!current_camera || !current_camera.can_use()) + for(var/obj/machinery/camera/current_camera as anything in cameras["[z_level]"]) + if(!current_camera?.can_use()) continue var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), z_level) - if(get_dist(point, current_camera) > CHUNK_SIZE + (CHUNK_SIZE / 2)) + if(get_dist(point, current_camera) > MAX_CAMERA_RANGE + (CHUNK_SIZE / 2)) continue // The return value of can_see being the left-hand operand here is a load-bearing performance pillar for(var/turf/vis_turf as anything in current_camera.can_see() & turfs) updated_visible_turfs[vis_turf] = vis_turf + update_with_turfs(updated_visible_turfs) + +/// Takes a list of newly visible turfs, updates our static images to match +/datum/camerachunk/proc/update_with_turfs(list/updated_visible_turfs) ///new turfs that we couldnt see last update but can now var/list/newly_visible_turfs = updated_visible_turfs - visibleTurfs ///turfs that we could see last update but cant see now @@ -176,22 +249,18 @@ var/turf/upper_turf = get_highest_turf(locate(x, y, lower_z)) src.upper_z = upper_turf.z + var/list/cameras = src.cameras + var/list/turfs = src.turfs + var/list/visibleTurfs = src.visibleTurfs + var/list/obscuredTurfs = src.obscuredTurfs + var/list/active_static_images = src.active_static_images + var/lower_x = x + var/lower_y = y + var/upper_x = min(lower_x + CHUNK_SIZE - 1, world.maxx) + var/upper_y = min(lower_y + CHUNK_SIZE - 1, world.maxy) + var/list/stack = SSmapping.get_connected_levels(lower_z) for(var/z_level in lower_z to upper_z) - var/list/local_cameras = list() - for(var/obj/machinery/camera/camera in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z_level))) - if(camera.can_use()) - local_cameras += camera - - for(var/mob/living/silicon/sillycone in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z_level))) - if(sillycone.builtInCamera?.can_use()) - local_cameras += sillycone.builtInCamera - - for(var/obj/vehicle/sealed/mecha/mech in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z_level))) - if(mech.chassis_camera?.can_use()) - local_cameras += mech.chassis_camera - - cameras[z_level] = local_cameras - + cameras["[z_level]"] = list() var/image/mirror_from = SScameras.obscured_images[GET_Z_PLANE_OFFSET(z_level) + 1] var/turf/chunk_corner = locate(x, y, z_level) for(var/turf/lad as anything in CORNER_BLOCK(chunk_corner, CHUNK_SIZE, CHUNK_SIZE)) //we use CHUNK_SIZE for width and height here as it handles subtracting 1 from those two parameters by itself @@ -199,15 +268,21 @@ our_image.loc = lad turfs[lad] = our_image - for(var/obj/machinery/camera/camera as anything in local_cameras) - if(!camera) - continue + for(var/obj/machinery/camera/camera as anything in SScameras.cameras) + var/turf/camera_loc = get_turf(camera) + // AABB + if(camera_loc.x + MAX_CAMERA_RANGE < lower_x || camera_loc.x - MAX_CAMERA_RANGE > upper_x) + continue + if(camera_loc.y + MAX_CAMERA_RANGE < lower_y || camera_loc.y - MAX_CAMERA_RANGE > upper_y) + continue + if(stack != SSmapping.get_connected_levels(camera_loc.z)) + continue + if(!camera.can_use()) + continue - if(!camera.can_use()) - continue - - for(var/turf/vis_turf as anything in camera.can_see() & turfs) - visibleTurfs[vis_turf] = vis_turf + cameras["[camera_loc.z]"] += camera + for(var/turf/vis_turf as anything in camera.can_see() & turfs) + visibleTurfs[vis_turf] = vis_turf for(var/turf/obscured_turf as anything in turfs - visibleTurfs) var/image/new_static = turfs[obscured_turf] diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index b22e81b8907..789dc1ef1d8 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -42,7 +42,6 @@ var/law_change_counter = 0 var/obj/machinery/camera/silicon/builtInCamera - var/updating = FALSE //portable camera camerachunk update ///Whether we have been emagged var/emagged = FALSE var/hack_software = FALSE //Will be able to use hacking actions diff --git a/code/modules/mob/living/silicon/silicon_movement.dm b/code/modules/mob/living/silicon/silicon_movement.dm index 7ead122301b..353399d5ac9 100644 --- a/code/modules/mob/living/silicon/silicon_movement.dm +++ b/code/modules/mob/living/silicon/silicon_movement.dm @@ -1,24 +1,7 @@ //We only call a camera static update if we have successfully moved and the camera is present and working /mob/living/silicon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() - if(builtInCamera?.can_use()) - update_camera_location(old_loc) - -/mob/living/silicon/proc/update_camera_location(oldLoc) - oldLoc = get_turf(oldLoc) - if(!updating && oldLoc != get_turf(src)) - updating = TRUE - do_camera_update(oldLoc) - -///The static update delay on movement of the camera in a borg we use -#define SILICON_CAMERA_BUFFER 0.5 SECONDS - -/** - * The actual update - also passes our unique update buffer. This makes our static update faster than stationary cameras, - * helping us to avoid running out of the camera's FoV. -*/ -/mob/living/silicon/proc/do_camera_update(oldLoc) - if(oldLoc != get_turf(src)) - SScameras.update_portable_camera(builtInCamera, SILICON_CAMERA_BUFFER) - updating = FALSE -#undef SILICON_CAMERA_BUFFER + if(!builtInCamera?.can_use()) + return + // Delay's a bit faster then standard cameras to "avoid running out of the camera's fov" whatever that means + SScameras.camera_moved(builtInCamera, get_turf(old_loc), get_turf(builtInCamera), 0.5 SECONDS) diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index 491d1402512..c488e1d0ec6 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -172,7 +172,7 @@ var/datum/camerachunk/target_camerachunk = SScameras.get_turf_camera_chunk(target_turf) if(!target_camerachunk) CRASH("[src] was able to track [target] through /datum/trackable, but was not on a visible turf to cameras.") - for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras[target.z]) + for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras["[target.z]"]) // We need to find a particular camera that can see this turf if(length(cameras.can_see() & list(target_turf))) continue diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 9155c307aef..4aa974f0de3 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -83,8 +83,6 @@ var/list/trackers = list() ///Camera installed into the mech var/obj/machinery/camera/exosuit/chassis_camera - ///Portable camera camerachunk update - var/updating = FALSE var/max_temperature = 25000 diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index 46b49cc2ee5..5477f5f2581 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -186,25 +186,8 @@ //We only call a camera static update if we have successfully moved and have a camera installed /obj/vehicle/sealed/mecha/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() - if(chassis_camera) - update_camera_location(old_loc) - -/obj/vehicle/sealed/mecha/proc/update_camera_location(oldLoc) - oldLoc = get_turf(oldLoc) - if(!updating && oldLoc != get_turf(src)) - updating = TRUE - do_camera_update(oldLoc) - -///The static update delay on movement of the camera in a mech we use -#define MECH_CAMERA_BUFFER 0.5 SECONDS - -/** - * The actual update - also passes our unique update buffer. This makes our static update faster than stationary cameras, - * helping us to avoid running out of the camera's FoV. An EMPd mecha with a lowered view_range on its camera can still - * sometimes run out into static before updating, however. -*/ -/obj/vehicle/sealed/mecha/proc/do_camera_update(oldLoc) - if(oldLoc != get_turf(src)) - SScameras.update_portable_camera(chassis_camera, MECH_CAMERA_BUFFER) - updating = FALSE -#undef MECH_CAMERA_BUFFER + if(!chassis_camera?.can_use()) + return + // Delay's a bit faster then standard cameras to "avoid running out of the camera's fov" whatever that means + // An EMPd mecha with a lowered view_range on its camera can still sometimes run out into static before updating, however. + SScameras.camera_moved(chassis_camera, get_turf(old_loc), get_turf(chassis_camera), 0.5 SECONDS) diff --git a/code/modules/wiremod/components/atom/remotecam.dm b/code/modules/wiremod/components/atom/remotecam.dm index 070d164c01c..3a1bbd3be47 100644 --- a/code/modules/wiremod/components/atom/remotecam.dm +++ b/code/modules/wiremod/components/atom/remotecam.dm @@ -189,7 +189,9 @@ /obj/item/circuit_component/remotecam/proc/update_camera_location(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) SIGNAL_HANDLER if(current_camera_state && current_cameranet_state) - SScameras.update_portable_camera(shell_camera, 0.5 SECONDS) + if(!shell_camera?.can_use()) + return + SScameras.camera_moved(shell_camera, get_turf(old_loc), get_turf(shell_camera), 0.5 SECONDS) /** * Add camera from global cameranet