diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index a002b4bef93..9521983acd8 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -158,6 +158,7 @@ #define FIRE_PRIORITY_PARALLAX 65 #define FIRE_PRIORITY_INSTRUMENTS 80 #define FIRE_PRIORITY_FLUIDS 80 +#define FIRE_PRIORITY_CAMERAS 85 #define FIRE_PRIORITY_PRIORITY_EFFECTS 90 #define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_TGUI 110 diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index a8100f6a7a0..1135c93b055 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -403,6 +403,15 @@ . = view(range, source) source.luminosity = lum +/// 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 + . = list() + for(var/turf/turf in view(range, source)) + . += turf + source.luminosity = lum + ///Returns the open turf next to the center in a specific direction /proc/get_open_turf_in_dir(atom/center, dir) var/turf/open/get_turf = get_step(center, dir) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 1f5c943d454..394fe4cd206 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -294,4 +294,4 @@ // /mob/living/silicon/ai/TurfAdjacent(turf/target_turf) - return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(target_turf)) + return (SScameras.is_visible_by_cameras(target_turf)) diff --git a/code/controllers/subsystem/cameras.dm b/code/controllers/subsystem/cameras.dm new file mode 100644 index 00000000000..5f5e9a2ec1b --- /dev/null +++ b/code/controllers/subsystem/cameras.dm @@ -0,0 +1,296 @@ +/// Manages the security cameras and camera chunks +SUBSYSTEM_DEF(cameras) + name = "Cameras" + flags = SS_BACKGROUND + priority = FIRE_PRIORITY_CAMERAS + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + wait = 2 MINUTES + dependencies = list( + // Required to get plane offset for static images + /datum/controller/subsystem/mapping, + ) + + /// The cameras on the map, no matter if they work or not. + /// Updated in obj/machinery/camera.dm in Initialize() and Destroy(). + var/list/obj/machinery/camera/cameras = list() + /// The chunks of the map, mapping the areas that the cameras can see. + var/list/chunks = list() + /// Chunks that must be updated + var/list/chunks_to_update = list() + /// List of images cloned by all chunk static images put onto turfs cameras cant see + /// Indexed by the plane offset to use + var/list/image/obscured_images = list() + /// Primarily for debugging, outright prevents all camera chunk updates + var/disable_camera_updates = FALSE + /// Tracks current subsystem run + var/list/current_run = list() + +/datum/controller/subsystem/cameras/Initialize() + update_offsets(SSmapping.max_plane_offset) + RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_growth)) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/cameras/fire(resumed = FALSE) + if(!resumed) + src.current_run = chunks_to_update.Copy() + chunks_to_update = list() + + 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(MC_TICK_CHECK) + break + +/datum/controller/subsystem/cameras/stat_entry(msg) + msg = "Cams: [length(cameras)] | Chunks: [length(chunks)] | Updating: [length(chunks_to_update)]" + return ..() + +/// Updates the images for new plane offsets +/datum/controller/subsystem/cameras/proc/update_offsets(new_offset) + for(var/i in length(obscured_images) to new_offset) + var/image/obscured = new('icons/effects/cameravis.dmi') + SET_PLANE_W_SCALAR(obscured, CAMERA_STATIC_PLANE, i) + obscured.appearance_flags = RESET_TRANSFORM | RESET_ALPHA | RESET_COLOR | KEEP_APART + obscured.override = TRUE + obscured_images += obscured + +/datum/controller/subsystem/cameras/proc/on_offset_growth(datum/source, old_offset, new_offset) + SIGNAL_HANDLER + update_offsets(new_offset) + +/// Checks if a chunk has been generated in x, y, z. +/datum/controller/subsystem/cameras/proc/get_camera_chunk(x, y, z) + x = GET_CHUNK_COORD(x) + y = GET_CHUNK_COORD(y) + if(GET_LOWEST_STACK_OFFSET(z) != 0) + var/turf/lowest = get_lowest_turf(locate(x, y, z)) + return chunks["[x],[y],[lowest.z]"] + + return chunks["[x],[y],[z]"] + +// Returns the chunk in the x, y, z. +// If there is no chunk, it creates a new chunk and returns that. +/datum/controller/subsystem/cameras/proc/generate_chunk(x, y, z) + x = GET_CHUNK_COORD(x) + y = GET_CHUNK_COORD(y) + var/turf/lowest = get_lowest_turf(locate(x, y, z)) + var/key = "[x],[y],[lowest.z]" + . = chunks[key] + if(!.) + . = new /datum/camerachunk(x, y, lowest.z) + chunks[key] = . + +/// Updates what the camera eye can see. +/// It is recommended you use this when a camera eye moves or its location is set. +/datum/controller/subsystem/cameras/proc/update_eye_chunk(mob/eye/camera/eye) + var/list/visibleChunks = list() + //Get the eye's turf in case its located in an object like a mecha + var/turf/eye_turf = get_turf(eye) + if(eye.loc) + var/static_range = eye.static_visibility_range + var/x1 = max(1, eye_turf.x - static_range) + var/y1 = max(1, eye_turf.y - static_range) + var/x2 = min(world.maxx, eye_turf.x + static_range) + var/y2 = min(world.maxy, eye_turf.y + static_range) + + for(var/x = x1; x <= x2; x += CHUNK_SIZE) + for(var/y = y1; y <= y2; y += CHUNK_SIZE) + visibleChunks |= generate_chunk(x, y, eye_turf.z) + + var/list/remove = eye.visibleCameraChunks - visibleChunks + var/list/add = visibleChunks - eye.visibleCameraChunks + + for(var/datum/camerachunk/chunk as anything in remove) + chunk.remove(eye) + + for(var/datum/camerachunk/chunk as anything in add) + chunk.add(eye) + +/// Used in [/proc/major_chunk_change] - indicates the camera should be removed from the chunk list. +#define REMOVE_CAMERA 0 +/// Used in [/proc/major_chunk_change] - indicates the camera should be added to the chunk list. +#define ADD_CAMERA 1 +/// Used in [/proc/major_chunk_change] - indicates the chunk should be updated without adding/removing a camera. +#define IGNORE_CAMERA 2 + +/// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open. +/datum/controller/subsystem/cameras/proc/update_visibility(atom/relevant_atom) + if(!SSticker) + return + major_chunk_change(relevant_atom, IGNORE_CAMERA) + +/// Removes a camera from a chunk. +/datum/controller/subsystem/cameras/proc/remove_camera_from_chunk(obj/machinery/camera/old_cam) + major_chunk_change(old_cam, REMOVE_CAMERA) + +/// Add a camera to a chunk. +/datum/controller/subsystem/cameras/proc/add_camera_to_chunk(obj/machinery/camera/new_cam) + if(new_cam.can_use()) + 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. +*/ +/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) + +/** + * Never access this proc directly!!!! + * This will update the chunk and all the surrounding chunks. + * It will also add the atom to the cameras list if you set the choice to 1. + * Setting the choice to 0 will remove the camera from the chunks. + * If you want to update the chunks around an object, without adding/removing a camera, use choice 2. + * update_delay_buffer is passed all the way to queue_update() from portable camera updates on movement + * to change the time between static updates. + */ +/datum/controller/subsystem/cameras/proc/major_chunk_change(atom/center_or_camera, choice = IGNORE_CAMERA, update_delay_buffer = 0) + PROTECTED_PROC(TRUE) + + if(QDELETED(center_or_camera) && choice == ADD_CAMERA) + CRASH("Tried to add a qdeleting camera to the net") + + var/turf/chunk_turf = get_turf(center_or_camera) + 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)) + 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) + if(isnull(chunk)) + continue + if(choice == REMOVE_CAMERA) + // Remove the 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.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)) + 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) + chunk?.queue_update(changed, 0) + +/// Will check if an atom is on a viewable turf. +/// Returns TRUE if the atom is visible by any camera, FALSE otherwise. +/datum/controller/subsystem/cameras/proc/is_visible_by_cameras(atom/target) + return turf_visible_by_cameras(get_turf(target)) + +/// Checks if the passed turf is visible by any camera. +/// Returns TRUE if the turf is visible by any camera, FALSE otherwise. +/datum/controller/subsystem/cameras/proc/turf_visible_by_cameras(turf/position) + PRIVATE_PROC(TRUE) + if(isnull(position)) + return FALSE + var/datum/camerachunk/chunk = generate_chunk(position.x, position.y, position.z) + if(isnull(chunk)) + return FALSE + chunk.force_update(only_if_necessary = TRUE) // Update NOW if necessary + if(chunk.visibleTurfs[position]) + return TRUE + return FALSE + +/// Gets the camera chunk the passed turf is in. +/// Returns the chunk if it exists and is visible, null otherwise. +/datum/controller/subsystem/cameras/proc/get_turf_camera_chunk(turf/position) + RETURN_TYPE(/datum/camerachunk) + var/datum/camerachunk/chunk = generate_chunk(position.x, position.y, position.z) + if(!chunk) + return null + chunk.force_update(only_if_necessary = TRUE) // Update NOW if necessary + if(chunk.visibleTurfs[position]) + return chunk + return null + +/// Returns list of available cameras, ready to use for UIs displaying list of them +/// The format is: list("name" = "camera.c_tag", ref = REF(camera)) +/datum/controller/subsystem/cameras/proc/get_available_cameras_data(list/networks_available, list/z_levels_available) + var/list/available_cameras_data = list() + for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available)) + available_cameras_data += list(list( + name = camera.c_tag, + ref = REF(camera), + )) + + return available_cameras_data + +/** + * get_available_camera_by_tag_list + * + * Builds a list of all available cameras that can be seen to networks_available and in z_levels_available. + * Entries are stored in `c_tag[camera.can_use() ? null : " (Deactivated)"]` => `camera` format + * Args: + * networks_available - List of networks that we use to see which cameras are visible to it. + * z_levels_available - List of z levels to filter camera by. If empty, all z levels are considered valid. + * sort_by_ctag - If the resulting list should be sorted by `c_tag`. + */ +/datum/controller/subsystem/cameras/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available) + var/list/available_cameras_by_tag = list() + for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available)) + available_cameras_by_tag["[camera.c_tag][camera.can_use() ? null : " (Deactivated)"]"] = camera + + return available_cameras_by_tag + +/// Returns list of all cameras that passed `is_camera_available` filter and sorted by `cmp_camera_ctag_asc` +/datum/controller/subsystem/cameras/proc/get_filtered_and_sorted_cameras(list/networks_available, list/z_levels_available) + PRIVATE_PROC(TRUE) + + var/list/filtered_cameras = list() + for(var/obj/machinery/camera/camera as anything in cameras) + if(!is_camera_available(camera, networks_available, z_levels_available)) + continue + + filtered_cameras += camera + + return sortTim(filtered_cameras, GLOBAL_PROC_REF(cmp_camera_ctag_asc)) + +/// Checks if the `camera_to_check` meets the requirements of availability. +/datum/controller/subsystem/cameras/proc/is_camera_available(obj/machinery/camera/camera_to_check, list/networks_available, list/z_levels_available) + PRIVATE_PROC(TRUE) + + if(!camera_to_check.c_tag) + return FALSE + + if(length(z_levels_available) && !(camera_to_check.z in z_levels_available)) + return FALSE + + return length(camera_to_check.network & networks_available) > 0 + +#undef ADD_CAMERA +#undef REMOVE_CAMERA +#undef IGNORE_CAMERA + +/obj/effect/overlay/camera_static + name = "static" + icon = null + icon_state = null + anchored = TRUE // should only appear in vis_contents, but to be safe + appearance_flags = RESET_TRANSFORM | TILE_BOUND | LONG_GLIDE + // this combination makes the static block clicks to everything below it, + // without appearing in the right-click menu for non-AI clients + mouse_opacity = MOUSE_OPACITY_ICON + invisibility = INVISIBILITY_ABSTRACT + + plane = CAMERA_STATIC_PLANE + +ADMIN_VERB(pause_camera_updates, R_ADMIN, "Toggle Camera Updates", "Stop security cameras from updating, meaning what they see now is what they will see forever.", ADMIN_CATEGORY_DEBUG) + SScameras.disable_camera_updates = !SScameras.disable_camera_updates + log_admin("[key_name_admin(user)] [SScameras.disable_camera_updates ? "disabled" : "enabled"] camera updates.") + message_admins("Admin [key_name_admin(user)] has [SScameras.disable_camera_updates ? "disabled" : "enabled"] camera updates.") + BLACKBOX_LOG_ADMIN_VERB("Toggle Camera Updates") diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index d7d4b38793d..53e724b4543 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -220,7 +220,6 @@ SUBSYSTEM_DEF(statpanels) #endif for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems) mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), text_ref(sub_system)) - mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", text_ref(GLOB.cameranet)) ///immediately update the active statpanel tab of the target client /datum/controller/subsystem/statpanels/proc/immediate_send_stat_data(client/target) diff --git a/code/datums/components/simple_bodycam.dm b/code/datums/components/simple_bodycam.dm index 9d653f38a78..1723a7a0a5a 100644 --- a/code/datums/components/simple_bodycam.dm +++ b/code/datums/components/simple_bodycam.dm @@ -56,7 +56,7 @@ do_update_cam() /datum/component/simple_bodycam/proc/do_update_cam() - GLOB.cameranet.updatePortableCamera(bodycam, camera_update_time) + SScameras.update_portable_camera(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/_machinery.dm b/code/game/machinery/_machinery.dm index 2023722ea35..6abdd7900ed 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -738,7 +738,7 @@ var/mob/user = ui.user add_fingerprint(user) update_last_used(user) - if(isAI(user) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs/adminghosts/human wand can still access off-camera stuff. + if(isAI(user) && !SScameras.is_visible_by_cameras(get_turf(src))) //We check if they're an AI specifically here, so borgs/adminghosts/human wand can still access off-camera stuff. to_chat(user, span_warning("You can no longer connect to this device!")) return FALSE return ..() diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 6d214d6781b..f323ddc30ac 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -110,12 +110,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) network -= network_name network += LOWER_TEXT(network_name) - GLOB.cameranet.cameras += src + SScameras.cameras += src myarea = get_room_area() if(camera_enabled) - GLOB.cameranet.addCamera(src) + SScameras.add_camera_to_chunk(src) LAZYADD(myarea.cameras, src) #ifdef MAP_TEST update_appearance() @@ -133,8 +133,8 @@ 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 - GLOB.cameranet.removeCamera(src) - GLOB.cameranet.cameras -= src + SScameras.remove_camera_from_chunk(src) + SScameras.cameras -= src cancelCameraAlarm() if(isarea(myarea)) LAZYREMOVE(myarea.cameras, src) @@ -219,7 +219,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) if(!prob(150 / severity)) return network = list() - GLOB.cameranet.removeCamera(src) + SScameras.remove_camera_from_chunk(src) set_machine_stat(machine_stat | EMPED) set_light(0) emped++ //Increase the number of consecutive EMP's @@ -246,7 +246,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) set_machine_stat(machine_stat & ~EMPED) update_appearance() if(can_use()) - GLOB.cameranet.addCamera(src) + SScameras.add_camera_to_chunk(src) emped = 0 //Resets the consecutive EMP count addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS) @@ -259,7 +259,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) /obj/machinery/camera/proc/setViewRange(num = 7) src.view_range = num - GLOB.cameranet.updateVisibility(src, 0) + SScameras.update_visibility(src) /obj/machinery/camera/proc/shock(mob/living/user) if(!istype(user)) @@ -336,7 +336,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) /obj/machinery/camera/proc/toggle_cam(mob/user, displaymessage = TRUE) camera_enabled = !camera_enabled if(can_use()) - GLOB.cameranet.addCamera(src) + SScameras.add_camera_to_chunk(src) if (isturf(loc)) myarea = get_area(src) LAZYADD(myarea.cameras, src) @@ -344,12 +344,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) myarea = null else set_light(0) - GLOB.cameranet.removeCamera(src) + SScameras.remove_camera_from_chunk(src) if (isarea(myarea)) LAZYREMOVE(myarea.cameras, src) // We are not guarenteed that the camera will be on a turf. account for that - var/turf/our_turf = get_turf(src) - GLOB.cameranet.updateChunk(our_turf.x, our_turf.y, our_turf.z) var/change_msg = "deactivates" if(camera_enabled) change_msg = "reactivates" @@ -389,6 +387,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) return FALSE return TRUE +/// Returns a list of turfs in this camera's view. +/// This includes turfs that are "obscured by darkness" from the camera's POV. /obj/machinery/camera/proc/can_see() var/list/see = null var/turf/pos = get_turf(src) @@ -397,26 +397,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) var/check_higher = directly_above && istransparentturf(directly_above) && (pos != get_highest_turf(pos)) if(isXRay()) - see = range(view_range, pos) + see = RANGE_TURFS(view_range, pos) else - see = get_hear(view_range, pos) + see = get_hear_turfs(view_range, pos) + if(check_lower || check_higher) // Haha datum var access KILL ME - for(var/turf/seen in see) + for(var/turf/seen as anything in see) if(check_lower) - var/turf/visible = seen - while(visible && istransparentturf(visible)) - var/turf/below = GET_TURF_BELOW(visible) - for(var/turf/adjacent in range(1, below)) - see += adjacent - see += adjacent.contents - visible = below + var/turf/below = GET_TURF_BELOW(seen) + while(below && istransparentturf(below)) + see += RANGE_TURFS(1, below) + below = GET_TURF_BELOW(below) if(check_higher) var/turf/above = GET_TURF_ABOVE(seen) while(above && istransparentturf(above)) - for(var/turf/adjacent in range(1, above)) - see += adjacent - see += adjacent.contents + see += RANGE_TURFS(1, above) above = GET_TURF_ABOVE(above) return see diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 89af3fc1192..7383db15f66 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -185,6 +185,7 @@ camera_upgrade_bitflags |= CAMERA_UPGRADE_XRAY update_appearance() + SScameras.update_visibility(src) /obj/machinery/camera/proc/removeXRay(ignore_malf_upgrades) if(!ignore_malf_upgrades) //don't downgrade it if malf software is forced onto it. diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 8725bda22f5..f33cff0c7ea 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -89,7 +89,7 @@ var/list/data = list() data["network"] = network data["mapRef"] = cam_screen.assigned_map - data["cameras"] = GLOB.cameranet.get_available_cameras_data(network) + data["cameras"] = SScameras.get_available_cameras_data(network) return data /obj/machinery/computer/security/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) @@ -99,7 +99,7 @@ if(action == "switch_camera") active_camera?.on_stop_watching(src) - var/obj/machinery/camera/selected_camera = locate(params["camera"]) in GLOB.cameranet.cameras + var/obj/machinery/camera/selected_camera = locate(params["camera"]) in SScameras.cameras active_camera = selected_camera if(isnull(active_camera)) diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index bb034b1a322..c364afa9ec3 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -183,10 +183,10 @@ else camera_location = myturf else - if((!consider_zlock || (myturf.z in z_lock)) && GLOB.cameranet.checkTurfVis(myturf)) + if((!consider_zlock || (myturf.z in z_lock)) && SScameras.is_visible_by_cameras(myturf)) camera_location = myturf else - for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/C as anything in SScameras.cameras) if(!C.can_use() || consider_zlock && !(C.z in z_lock)) continue var/list/network_overlap = networks & C.network @@ -229,7 +229,7 @@ var/mob/eye/camera/remote/remote_eye = owner.remote_control var/obj/machinery/computer/camera_advanced/origin = remote_eye.origin_ref.resolve() - var/list/cameras_by_tag = GLOB.cameranet.get_available_camera_by_tag_list(origin.networks, origin.z_lock) + var/list/cameras_by_tag = SScameras.get_available_camera_by_tag_list(origin.networks, origin.z_lock) playsound(origin, 'sound/machines/terminal/terminal_prompt.ogg', 25, FALSE) var/camera = tgui_input_list(usr, "Camera to view", "Cameras", cameras_by_tag) @@ -403,7 +403,7 @@ var/turf/eye_turf = get_turf(source) if(!eye_turf) return - if(!GLOB.cameranet.checkTurfVis(eye_turf)) + if(!SScameras.is_visible_by_cameras(eye_turf)) return eye_x.set_output(source.x) eye_y.set_output(source.y) @@ -490,7 +490,7 @@ var/turf/target_turf = get_turf(target) if(!target_turf) return - if(!GLOB.cameranet.checkTurfVis(target_turf)) + if(!SScameras.is_visible_by_cameras(target_turf)) return if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_TARGET_INTERCEPT)) return diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index aea2ac558f7..65ce845a44b 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1356,10 +1356,9 @@ set_airlock_state(AIRLOCK_OPENING, animated = TRUE, force_type = forced) var/transparent_delay = animation_segment_delay(AIRLOCK_OPENING_TRANSPARENT) sleep(transparent_delay) - set_opacity(0) + set_opacity(FALSE) if(multi_tile) filler.set_opacity(FALSE) - update_freelook_sight() var/passable_delay = animation_segment_delay(AIRLOCK_OPENING_PASSABLE) - transparent_delay sleep(passable_delay) set_density(FALSE) @@ -1446,7 +1445,6 @@ set_opacity(TRUE) if(multi_tile) filler.set_opacity(TRUE) - update_freelook_sight() var/close_delay = animation_segment_delay(AIRLOCK_CLOSING_FINISHED) - unpassable_delay - opaque_delay sleep(close_delay) set_airlock_state(AIRLOCK_CLOSED, animated = FALSE) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 697de876023..daecb318bb8 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -98,7 +98,6 @@ set_bounds() set_filler() update_overlays() - update_freelook_sight() air_update_turf(TRUE, TRUE) register_context() if(elevator_mode) @@ -163,7 +162,6 @@ layer = initial(layer) /obj/machinery/door/Destroy() - update_freelook_sight() if(elevator_mode) GLOB.elevator_doors -= src if(spark_system) @@ -508,7 +506,7 @@ operating = TRUE use_energy(active_power_usage) run_animation(DOOR_OPENING_ANIMATION) - set_opacity(0) + set_opacity(FALSE) var/passable_delay = animation_segment_delay(DOOR_OPENING_PASSABLE) SLEEP_NOT_DEL(passable_delay) set_density(FALSE) @@ -517,10 +515,9 @@ SLEEP_NOT_DEL(open_delay) layer = initial(layer) update_appearance() - set_opacity(0) + set_opacity(FALSE) operating = FALSE air_update_turf(TRUE, FALSE) - update_freelook_sight() if(autoclose) autoclose_in(DOOR_CLOSE_WAIT) return TRUE @@ -556,10 +553,9 @@ SLEEP_NOT_DEL(close_delay) update_appearance() if(visible && !glass) - set_opacity(1) + set_opacity(TRUE) operating = FALSE air_update_turf(TRUE, TRUE) - update_freelook_sight() if(!can_crush) return TRUE @@ -618,10 +614,6 @@ /obj/machinery/door/proc/hasPower() return !(machine_stat & NOPOWER) -/obj/machinery/door/proc/update_freelook_sight() - if(!glass && GLOB.cameranet) - GLOB.cameranet.updateVisibility(src, 0) - /obj/machinery/door/block_superconductivity() // All non-glass airlocks block heat, this is intended. if(opacity || heat_proof) return 1 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 8ede2092a4c..7579756590f 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -256,7 +256,6 @@ var/open_delay = animation_segment_delay(DOOR_OPENING_FINISHED) - passable_delay sleep(open_delay) air_update_turf(TRUE, FALSE) - update_freelook_sight() if(operating == 1) //emag again operating = FALSE @@ -299,7 +298,6 @@ sleep(unpassable_delay) set_density(TRUE) air_update_turf(TRUE, TRUE) - update_freelook_sight() var/close_delay = animation_segment_delay(DOOR_CLOSING_FINISHED) - unpassable_delay sleep(close_delay) @@ -549,8 +547,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holding operating = TRUE set_density(FALSE) + set_opacity(FALSE) air_update_turf(TRUE, FALSE) - update_freelook_sight() operating = FALSE update_appearance() @@ -564,8 +562,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holding operating = TRUE set_density(TRUE) + set_opacity(TRUE) air_update_turf(TRUE, TRUE) - update_freelook_sight() operating = FALSE update_appearance() diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index 6ddd65f12cf..73ffc52a2bd 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -12,14 +12,6 @@ would spawn and follow the beaker, even if it is carried or thrown. pass_flags = PASSTABLE | PASSGRILLE anchored = TRUE -/obj/effect/particle_effect/Initialize(mapload) - . = ..() - GLOB.cameranet.updateVisibility(src) - -/obj/effect/particle_effect/Destroy() - GLOB.cameranet.updateVisibility(src) - return ..() - // Prevents effects from getting registered for SSnewtonian_movement /obj/effect/particle_effect/newtonian_move(inertia_angle, instant = FALSE, start_delay = 0, drift_force = 0, controlled_cap = null) return TRUE diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index e7244491423..626c42d65a4 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -295,10 +295,10 @@ for(var/x = x1; x <= x2; x += CHUNK_SIZE) for(var/y = y1; y <= y2; y += CHUNK_SIZE) - var/datum/camerachunk/chunk = GLOB.cameranet.getCameraChunk(x, y, epicenter.z) + var/datum/camerachunk/chunk = SScameras.generate_chunk(x, y, epicenter.z) // removing cameras in build mode didnt affect it and i guess it needs an AI eye to update so we have to do this manually // unless we only want to see static in a jank manner only if an eye updates it - chunk?.update() // UPDATE THE FUCK NOW + chunk?.force_update(only_if_necessary = FALSE) // UPDATE THE FUCK NOW . |= chunk /obj/item/multitool/ai_detect/proc/cleanup_static() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 10b500824e5..cc7cf0f2ccd 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -64,10 +64,14 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) if (id_tag) GLOB.objects_by_id_tag[id_tag] = src + if(opacity) + SScameras.update_visibility(src) /obj/Destroy(force) if(!ismachinery(src)) STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists + if(opacity) + SScameras.update_visibility(src) SStgui.close_uis(src) GLOB.objects_by_id_tag -= id_tag . = ..() diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 3e7e13c1df2..9d4442238ac 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -23,10 +23,8 @@ if(smoothing_flags & USES_SMOOTHING) QUEUE_SMOOTH(src) QUEUE_SMOOTH_NEIGHBORS(src) - GLOB.cameranet.updateVisibility(src) /obj/structure/Destroy(force) - GLOB.cameranet.updateVisibility(src) if(smoothing_flags & USES_SMOOTHING) QUEUE_SMOOTH_NEIGHBORS(src) return ..() diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 347a3574769..49ebdb577a9 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -193,7 +193,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( space_tile.enable_starlight() if(old_opacity != opacity && SSticker) - GLOB.cameranet.bareMajorChunkChange(src) + SScameras.bare_major_chunk_change(src) // We will only run this logic if the tile is not on the prime z layer, since we use area overlays to cover that if(SSmapping.z_level_to_plane_offset[z]) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 0243b866d82..53f75673d87 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -553,9 +553,6 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/proc/can_lay_cable() return can_have_cabling() && underfloor_accessibility >= UNDERFLOOR_INTERACTABLE -/turf/proc/visibilityChanged() - GLOB.cameranet.updateVisibility(src) - /turf/proc/burn_tile() return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index a981a5c3e74..47098fd8a3f 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -320,7 +320,7 @@ ADMIN_VERB(cmd_admin_areatest, R_DEBUG, "Test Areas", "Tests the areas for vario areas_with_intercom.Add(A.type) CHECK_TICK - for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/C as anything in SScameras.cameras) var/area/A = get_area(C) if(!A) dat += "Skipped over [C] in invalid location, [C.loc].
" diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index dcb9d902f31..8adfd07671e 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -8,11 +8,11 @@ ADMIN_VERB(camera_view, R_DEBUG, "Camera Range Display", "Shows the range of cam if(!on) var/list/seen = list() - for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) - for(var/turf/T in C.can_see()) - seen[T]++ - for(var/turf/T in seen) - T.maptext = MAPTEXT(seen[T]) + for(var/obj/machinery/camera/cam as anything in SScameras.cameras) + for(var/turf/cam_turf as anything in cam.can_see()) + seen[cam]++ + for(var/turf/seen_turf as anything in seen) + seen_turf.maptext = MAPTEXT(seen[seen_turf]) BLACKBOX_LOG_ADMIN_VERB("Show Camera Range") #ifdef TESTING @@ -34,7 +34,7 @@ ADMIN_VERB_VISIBILITY(sec_camera_report, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG ADMIN_VERB(sec_camera_report, R_DEBUG, "Camera Report", "Get a printout of all camera issues.", ADMIN_CATEGORY_MAPPING) var/list/obj/machinery/camera/CL = list() - for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/C as anything in SScameras.cameras) CL += C var/output = {"Camera Abnormalities Report
diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 0141ae73cbf..10abf2577ee 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -72,7 +72,7 @@ use_delay = (world.time + abductor_pad_cooldown) - if(GLOB.cameranet.checkTurfVis(remote_eye.loc)) + if(SScameras.is_visible_by_cameras(remote_eye.loc)) P.PadToLoc(remote_eye.loc) /datum/action/innate/teleport_out @@ -116,7 +116,7 @@ use_delay = (world.time + teleport_self_cooldown) - if(GLOB.cameranet.checkTurfVis(remote_eye.loc)) + if(SScameras.is_visible_by_cameras(remote_eye.loc)) P.MobToLoc(remote_eye.loc,C) /datum/action/innate/vest_mode_swap diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 433d87fcbc3..377caebf7ea 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -699,8 +699,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf)) var/turf/T = turfs[n] if(!isfloorturf(T)) success = FALSE - var/datum/camerachunk/C = GLOB.cameranet.getCameraChunk(T.x, T.y, T.z) - if(!C.visibleTurfs[T]) + if(!SScameras.is_visible_by_cameras(T)) alert_msg = "You don't have camera vision of this location!" success = FALSE for(var/atom/movable/AM in T.contents) @@ -825,7 +824,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf)) /datum/action/innate/ai/reactivate_cameras/Activate() var/fixed_cameras = 0 - for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/C as anything in SScameras.cameras) if(!uses) break if(!C.camera_enabled || C.view_range != initial(C.view_range)) @@ -857,13 +856,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf)) AI.update_sight() var/upgraded_cameras = 0 - for(var/obj/machinery/camera/camera as anything in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/camera as anything in SScameras.cameras) var/upgraded = FALSE if(!camera.isXRay()) camera.upgradeXRay(TRUE) //if this is removed you can get rid of camera_assembly/var/malf_xray_firmware_active and clean up isxray() //Update what it can see. - GLOB.cameranet.updateVisibility(camera, 0) upgraded = TRUE if(!camera.isEmpProof()) diff --git a/code/modules/events/camerafailure.dm b/code/modules/events/camerafailure.dm index d2fcdda8314..f6929d4768f 100644 --- a/code/modules/events/camerafailure.dm +++ b/code/modules/events/camerafailure.dm @@ -12,7 +12,7 @@ /datum/round_event/camera_failure/start() var/iterations = 1 - var/list/cameras = GLOB.cameranet.cameras.Copy() + var/list/cameras = SScameras.cameras.Copy() while(prob(round(100/iterations))) var/obj/machinery/camera/C = pick_n_take(cameras) if (!C) diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 21676d1741e..b671de56cfc 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -84,6 +84,8 @@ AddElement(/datum/element/light_blocking) else RemoveElement(/datum/element/light_blocking) + // Change in opacity could change camera visibility + SScameras.update_visibility(src) /turf/set_opacity(new_opacity) . = ..() diff --git a/code/modules/mining/lavaland/mining_loot/megafauna/the_thing.dm b/code/modules/mining/lavaland/mining_loot/megafauna/the_thing.dm index 19c04179d25..44172c5ed11 100644 --- a/code/modules/mining/lavaland/mining_loot/megafauna/the_thing.dm +++ b/code/modules/mining/lavaland/mining_loot/megafauna/the_thing.dm @@ -118,7 +118,7 @@ if(AI.controlled_equipment) to_chat(AI, span_warning("You are already loaded into an onboard computer!")) return - if(!GLOB.cameranet.checkCameraVis(owner)) + if(!SScameras.is_visible_by_cameras(owner)) to_chat(AI, span_warning("Target is no longer near active cameras.")) return if(!isturf(AI.loc)) diff --git a/code/modules/mob/eye/camera/camera.dm b/code/modules/mob/eye/camera/camera.dm index 58019f73859..8df02a444b2 100644 --- a/code/modules/mob/eye/camera/camera.dm +++ b/code/modules/mob/eye/camera/camera.dm @@ -71,7 +71,7 @@ SHOULD_CALL_PARENT(TRUE) if(use_visibility) - GLOB.cameranet.visibility(src) + SScameras.update_eye_chunk(src) /mob/eye/camera/zMove(dir, turf/target, z_move_flags = NONE, recursions_left = 1, list/falling_movs) . = ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9d86aa3eb06..c3a0f479558 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1328,7 +1328,7 @@ if(onSyndieBase() && !(ROLE_SYNDICATE in user?.faction)) return FALSE // Now, are they viewable by a camera? (This is last because it's the most intensive check) - if(!GLOB.cameranet.checkCameraVis(src)) + if(!SScameras.is_visible_by_cameras(src)) return FALSE return TRUE diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 9ad600b0f88..329a5f29823 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -310,7 +310,7 @@ return ISINRANGE(target_turf.x, ai_turf.x - interaction_range, ai_turf.x + interaction_range) \ && ISINRANGE(target_turf.y, ai_turf.y - interaction_range, ai_turf.y + interaction_range) else - return GLOB.cameranet.checkTurfVis(target_turf) + return SScameras.is_visible_by_cameras(target_turf) /mob/living/silicon/ai/cancel_camera() view_core() @@ -432,7 +432,7 @@ return if (href_list["switchcamera"]) - switchCamera(locate(href_list["switchcamera"]) in GLOB.cameranet.cameras) + switchCamera(locate(href_list["switchcamera"]) in SScameras.cameras) if (href_list["showalerts"]) alert_control.ui_interact(src) #ifdef AI_VOX @@ -475,7 +475,7 @@ if(controlled_equipment) to_chat(src, span_warning("You are already loaded into an onboard computer!")) return - if(!GLOB.cameranet.checkCameraVis(M)) + if(!SScameras.is_visible_by_cameras(M)) to_chat(src, span_warning("Exosuit is no longer near active cameras.")) return if(!isturf(loc)) @@ -520,7 +520,7 @@ //The target must be in view of a camera or near the core. if(turf_check in range(get_turf(src))) call_bot(turf_check) - else if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check)) + else if(SScameras.is_visible_by_cameras(turf_check)) call_bot(turf_check) else to_chat(src, span_danger("Selected location is not visible.")) @@ -578,7 +578,7 @@ var/mob/living/silicon/ai/U = usr - for (var/obj/machinery/camera/C in GLOB.cameranet.cameras) + for (var/obj/machinery/camera/C in SScameras.cameras) var/turf/camera_turf = get_turf(C) //get camera's turf in case it's built into something so we don't get z=0 var/list/tempnetwork = C.network @@ -600,7 +600,7 @@ if(isnull(network)) network = old_network // If nothing is selected else - for(var/obj/machinery/camera/C in GLOB.cameranet.cameras) + for(var/obj/machinery/camera/C in SScameras.cameras) if(!C.can_use()) continue if(network in C.network) @@ -806,7 +806,7 @@ if(isturf(loc)) //AI in core, check if on cameras //get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera //apc_override is needed here because AIs use their own APC when depowered - return ((GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A))) || (A == apc_override)) + return (SScameras.is_visible_by_cameras(get_turf_pixel(A)) || (A == apc_override)) //AI is carded/shunted //view(src) returns nothing for carded/shunted AIs and they have X-ray vision so just use get_dist var/list/viewscale = getviewsize(client.view) @@ -1045,7 +1045,7 @@ . = ..() /mob/living/silicon/ai/proc/camera_visibility(mob/eye/camera/ai/moved_eye) - GLOB.cameranet.visibility(moved_eye) + SScameras.update_eye_chunk(moved_eye) /mob/living/silicon/ai/forceMove(atom/destination) . = ..() @@ -1079,7 +1079,7 @@ REMOVE_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT) /mob/living/silicon/ai/proc/show_camera_list() - var/list/cameras = GLOB.cameranet.get_available_camera_by_tag_list(network) + var/list/cameras = SScameras.get_available_camera_by_tag_list(network) var/camera_tag = tgui_input_list(src, "Choose which camera you want to view", "Cameras", cameras) if(isnull(camera_tag)) return diff --git a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm deleted file mode 100644 index 5e534297d77..00000000000 --- a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm +++ /dev/null @@ -1,253 +0,0 @@ -// CAMERA NET -// -// The datum containing all the chunks. - -GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new) - -/datum/cameranet - /// Name to show for VV and stat() - var/name = "Camera Net" - - /// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm in Initialize() and Destroy(). - var/list/obj/machinery/camera/cameras = list() - /// The chunks of the map, mapping the areas that the cameras can see. - var/list/chunks = list() - - /// List of images cloned by all chunk static images put onto turfs cameras cant see - /// Indexed by the plane offset to use - var/list/image/obscured_images - -/datum/cameranet/New() - obscured_images = list() - update_offsets(SSmapping.max_plane_offset) - RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_growth)) - -/datum/cameranet/proc/update_offsets(new_offset) - for(var/i in length(obscured_images) to new_offset) - var/image/obscured = new('icons/effects/cameravis.dmi') - SET_PLANE_W_SCALAR(obscured, CAMERA_STATIC_PLANE, i) - obscured.appearance_flags = RESET_TRANSFORM | RESET_ALPHA | RESET_COLOR | KEEP_APART - obscured.override = TRUE - obscured_images += obscured - -/datum/cameranet/proc/on_offset_growth(datum/source, old_offset, new_offset) - SIGNAL_HANDLER - update_offsets(new_offset) - -/// Checks if a chunk has been Generated in x, y, z. -/datum/cameranet/proc/chunkGenerated(x, y, z) - x = GET_CHUNK_COORD(x) - y = GET_CHUNK_COORD(y) - if(GET_LOWEST_STACK_OFFSET(z) != 0) - var/turf/lowest = get_lowest_turf(locate(x, y, z)) - return chunks["[x],[y],[lowest.z]"] - - return chunks["[x],[y],[z]"] - -// Returns the chunk in the x, y, z. -// If there is no chunk, it creates a new chunk and returns that. -/datum/cameranet/proc/getCameraChunk(x, y, z) - x = GET_CHUNK_COORD(x) - y = GET_CHUNK_COORD(y) - var/turf/lowest = get_lowest_turf(locate(x, y, z)) - var/key = "[x],[y],[lowest.z]" - . = chunks[key] - if(!.) - chunks[key] = . = new /datum/camerachunk(x, y, lowest.z) - -/// Updates what the camera eye can see. It is recommended you use this when a camera eye moves or its location is set. -/datum/cameranet/proc/visibility(list/moved_eyes) - if(!islist(moved_eyes)) - moved_eyes = moved_eyes ? list(moved_eyes) : list() - - for(var/mob/eye/camera/eye as anything in moved_eyes) - var/list/visibleChunks = list() - //Get the eye's turf in case its located in an object like a mecha - var/turf/eye_turf = get_turf(eye) - if(eye.loc) - var/static_range = eye.static_visibility_range - var/x1 = max(1, eye_turf.x - static_range) - var/y1 = max(1, eye_turf.y - static_range) - var/x2 = min(world.maxx, eye_turf.x + static_range) - var/y2 = min(world.maxy, eye_turf.y + static_range) - - for(var/x = x1; x <= x2; x += CHUNK_SIZE) - for(var/y = y1; y <= y2; y += CHUNK_SIZE) - visibleChunks |= getCameraChunk(x, y, eye_turf.z) - - var/list/remove = eye.visibleCameraChunks - visibleChunks - var/list/add = visibleChunks - eye.visibleCameraChunks - - for(var/datum/camerachunk/chunk as anything in remove) - chunk.remove(eye) - - for(var/datum/camerachunk/chunk as anything in add) - chunk.add(eye) - -/// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open. -/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1) - if(!SSticker || (opacity_check && !A.opacity)) - return - majorChunkChange(A, 2) - -/datum/cameranet/proc/updateChunk(x, y, z) - var/datum/camerachunk/chunk = chunkGenerated(x, y, z) - if (!chunk) - return - chunk.hasChanged() - -/// Removes a camera from a chunk. -/datum/cameranet/proc/removeCamera(obj/machinery/camera/c) - majorChunkChange(c, 0) - -/// Add a camera to a chunk. -/datum/cameranet/proc/addCamera(obj/machinery/camera/c) - if(c.can_use()) - majorChunkChange(c, 1) - -/** - * Used for Cyborg/mecha cameras. Since portable cameras can be in ANY chunk. - * update_delay_buffer is passed all the way to hasChanged() from their camera updates on movement - * to change the time between static updates. -*/ -/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/updating_camera, update_delay_buffer) - if(updating_camera.can_use()) - majorChunkChange(updating_camera, 1, update_delay_buffer) - -/** - * Never access this proc directly!!!! - * This will update the chunk and all the surrounding chunks. - * It will also add the atom to the cameras list if you set the choice to 1. - * Setting the choice to 0 will remove the camera from the chunks. - * If you want to update the chunks around an object, without adding/removing a camera, use choice 2. - * update_delay_buffer is passed all the way to hasChanged() from portable camera updates on movement - * to change the time between static updates. - */ -/datum/cameranet/proc/majorChunkChange(atom/c, choice, update_delay_buffer) - PROTECTED_PROC(TRUE) - - if(QDELETED(c) && choice == 1) - CRASH("Tried to add a qdeleting camera to the net") - - var/turf/T = get_turf(c) - if(T) - var/x1 = max(1, T.x - (CHUNK_SIZE / 2)) - var/y1 = max(1, T.y - (CHUNK_SIZE / 2)) - var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) - var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) - for(var/x = x1; x <= x2; x += CHUNK_SIZE) - for(var/y = y1; y <= y2; y += CHUNK_SIZE) - var/datum/camerachunk/chunk = chunkGenerated(x, y, T.z) - if(chunk) - if(choice == 0) - // Remove the camera. - chunk.cameras["[T.z]"] -= c - else if(choice == 1) - // You can't have the same camera in the list twice. - chunk.cameras["[T.z]"] |= c - chunk.hasChanged(update_delay_buffer = update_delay_buffer) - -/// A faster, turf only version of [/datum/cameranet/proc/majorChunkChange] -/// For use in sensitive code, be careful with it -/datum/cameranet/proc/bareMajorChunkChange(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)) - for(var/x = x1; x <= x2; x += CHUNK_SIZE) - for(var/y = y1; y <= y2; y += CHUNK_SIZE) - var/datum/camerachunk/chunk = chunkGenerated(x, y, changed.z) - chunk?.hasChanged() - -/// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0. -/datum/cameranet/proc/checkCameraVis(mob/living/target) - var/turf/position = get_turf(target) - if(!position) - return - return checkTurfVis(position) - -/datum/cameranet/proc/checkTurfVis(turf/position) - var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z) - if(chunk) - if(chunk.changed) - chunk.hasChanged(1) // Update now, no matter if it's visible or not. - if(chunk.visibleTurfs[position]) - return TRUE - return FALSE - -/datum/cameranet/proc/getTurfVis(turf/position) - RETURN_TYPE(/datum/camerachunk) - var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z) - if(!chunk) - return FALSE - if(chunk.changed) - chunk.hasChanged(1) // Update now, no matter if it's visible or not. - if(chunk.visibleTurfs[position]) - return chunk - -/// Returns list of available cameras, ready to use for UIs displaying list of them -/// The format is: list("name" = "camera.c_tag", ref = REF(camera)) -/datum/cameranet/proc/get_available_cameras_data(list/networks_available, list/z_levels_available) - var/list/available_cameras_data = list() - for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available)) - available_cameras_data += list(list( - name = camera.c_tag, - ref = REF(camera), - )) - - return available_cameras_data - -/** - * get_available_camera_by_tag_list - * - * Builds a list of all available cameras that can be seen to networks_available and in z_levels_available. - * Entries are stored in `c_tag[camera.can_use() ? null : " (Deactivated)"]` => `camera` format - * Args: - * networks_available - List of networks that we use to see which cameras are visible to it. - * z_levels_available - List of z levels to filter camera by. If empty, all z levels are considered valid. - * sort_by_ctag - If the resulting list should be sorted by `c_tag`. - */ -/datum/cameranet/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available) - var/list/available_cameras_by_tag = list() - for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available)) - available_cameras_by_tag["[camera.c_tag][camera.can_use() ? null : " (Deactivated)"]"] = camera - - return available_cameras_by_tag - -/// Returns list of all cameras that passed `is_camera_available` filter and sorted by `cmp_camera_ctag_asc` -/datum/cameranet/proc/get_filtered_and_sorted_cameras(list/networks_available, list/z_levels_available) - PRIVATE_PROC(TRUE) - - var/list/filtered_cameras = list() - for(var/obj/machinery/camera/camera as anything in cameras) - if(!is_camera_available(camera, networks_available, z_levels_available)) - continue - - filtered_cameras += camera - - return sortTim(filtered_cameras, GLOBAL_PROC_REF(cmp_camera_ctag_asc)) - -/// Checks if the `camera_to_check` meets the requirements of availability. -/datum/cameranet/proc/is_camera_available(obj/machinery/camera/camera_to_check, list/networks_available, list/z_levels_available) - PRIVATE_PROC(TRUE) - - if(!camera_to_check.c_tag) - return FALSE - - if(length(z_levels_available) && !(camera_to_check.z in z_levels_available)) - return FALSE - - return length(camera_to_check.network & networks_available) > 0 - -/obj/effect/overlay/camera_static - name = "static" - icon = null - icon_state = null - anchored = TRUE // should only appear in vis_contents, but to be safe - appearance_flags = RESET_TRANSFORM | TILE_BOUND | LONG_GLIDE - // this combination makes the static block clicks to everything below it, - // without appearing in the right-click menu for non-AI clients - mouse_opacity = MOUSE_OPACITY_ICON - invisibility = INVISIBILITY_ABSTRACT - - plane = CAMERA_STATIC_PLANE diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm index a2dcee69cd1..23098ab15e9 100644 --- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm +++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm @@ -1,5 +1,3 @@ -#define UPDATE_BUFFER_TIME (2.5 SECONDS) - /** * A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. \ * Allows Camera Eyes to stream these chunks and know what it can and cannot see. @@ -12,7 +10,7 @@ var/list/visibleTurfs = list() ///cameras that can see into our grid ///indexed by the z level of the camera - var/list/cameras = list() + var/alist/cameras = alist() ///list of all turfs, associative with that turf's static image ///turf -> /image var/list/turfs = list() @@ -21,18 +19,19 @@ ///images currently in use on obscured turfs. var/list/active_static_images = list() - var/changed = FALSE var/x = 0 var/y = 0 var/lower_z var/upper_z -/// Add a camera eye to the chunk, then update if changed. + /// List of atoms that caused the chunk to update - assoc atom ref() to opacity on queue + var/list/update_sources = list() + +/// Add a camera eye to the chunk, updating the chunk if necessary. /datum/camerachunk/proc/add(mob/eye/camera/eye) eye.visibleCameraChunks += src seenby += eye - if(changed) - update() + force_update() var/client/client = eye.GetViewerClient() if(client && eye.use_visibility) @@ -47,36 +46,74 @@ if(client && eye.use_visibility && seenby.len == 0) client.images -= active_static_images -/// Called when a chunk has changed. I.E: A wall was deleted. -/datum/camerachunk/proc/visibilityChanged(turf/loc) - if(!visibleTurfs[loc]) +/** + * Queues the chuck to be updated after a delay. + * + * * update_source - the atom that caused the update + * * update_delay_buffer - the delay before the update is performed. Defaults to 0 (instant). + */ +/datum/camerachunk/proc/queue_update(atom/update_source, update_delay_buffer = 0) + // This chunk is being actively observed, skip queuing + if(length(seenby)) + addtimer(CALLBACK(src, PROC_REF(update)), update_delay_buffer || 1, TIMER_UNIQUE) return - hasChanged() + + // Only start queue if this is the first thing to queue an update + var/start_queue = !length(update_sources) + + var/update_key = REF(update_source) + // Camera updates will never be second guessed. + // Track the number of times the camera has queued an update instead of opacity (just for fun) + if(istype(update_source, /obj/machinery/camera)) + update_sources[update_source] += 1 + + // Otherwise track this atom's opacity at time of queue + else if(isnull(update_sources[update_key])) + update_sources[update_key] = update_source.opacity + + // If the tracked opacity does not match current opacity, + // that implies that the atom changed opacity twice in the time before the update happened + // 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 + return + + if(!start_queue) + return + + if(update_delay_buffer <= 0) + _queue_update() + else + addtimer(CALLBACK(src, PROC_REF(_queue_update)), update_delay_buffer, TIMER_UNIQUE) + +/datum/camerachunk/proc/_queue_update() + PRIVATE_PROC(TRUE) + // Something forced an update during the delay + if(!length(update_sources)) + return + SScameras.chunks_to_update[src] += 1 /** - * Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will - * instead be flagged to update the next time an AI Eye moves near it. + * Forces the chunk to update immediately * - * update_delay_buffer is used for cameras that are moving around, which are cyborg inbuilt cameras and - * mecha onboard cameras. This buffer should be usually lower than UPDATE_BUFFER_TIME because - * otherwise a moving camera can run out of its own view before updating static. + * * only_if_necessary - if TRUE, will not update the chunk unless it's been marked to update. */ -/datum/camerachunk/proc/hasChanged(update_now = 0, update_delay_buffer = UPDATE_BUFFER_TIME) - if(seenby.len || update_now) - addtimer(CALLBACK(src, PROC_REF(update)), update_delay_buffer, TIMER_UNIQUE) - else - changed = TRUE +/datum/camerachunk/proc/force_update(only_if_necessary = TRUE) + if(only_if_necessary && !length(update_sources)) + return + update() /// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists. -/// Accepts an optional partial_update argument, that blocks any calls out to chunks that could affect us, like above or below -/datum/camerachunk/proc/update(partial_update = FALSE) - if(GLOB.block_camera_updates) +/datum/camerachunk/proc/update() + if(SScameras.disable_camera_updates) return + update_sources.Cut() + 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]"]) + for(var/obj/machinery/camera/current_camera as anything in cameras[z_level]) if(!current_camera || !current_camera.can_use()) continue @@ -84,9 +121,8 @@ if(get_dist(point, current_camera) > CHUNK_SIZE + (CHUNK_SIZE / 2)) continue - for(var/turf/vis_turf in current_camera.can_see()) - if(turfs[vis_turf]) - updated_visible_turfs[vis_turf] = vis_turf + for(var/turf/vis_turf as anything in turfs & current_camera.can_see()) + updated_visible_turfs[vis_turf] = vis_turf ///new turfs that we couldnt see last update but can now var/list/newly_visible_turfs = updated_visible_turfs - visibleTurfs @@ -121,8 +157,6 @@ active_static_images += static_image visibleTurfs = updated_visible_turfs - changed = FALSE - for(var/mob/eye/camera/client_eye as anything in seenby) var/client/client = client_eye.GetViewerClient() if(!client) @@ -156,9 +190,9 @@ if(mech.chassis_camera?.can_use()) local_cameras += mech.chassis_camera - cameras["[z_level]"] = local_cameras + cameras[z_level] = local_cameras - var/image/mirror_from = GLOB.cameranet.obscured_images[GET_Z_PLANE_OFFSET(z_level) + 1] + 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 var/image/our_image = new /image(mirror_from) @@ -172,18 +206,10 @@ if(!camera.can_use()) continue - for(var/turf/vis_turf in camera.can_see()) - if(turfs[vis_turf]) - visibleTurfs[vis_turf] = vis_turf + for(var/turf/vis_turf as anything in turfs & camera.can_see()) + visibleTurfs[vis_turf] = vis_turf for(var/turf/obscured_turf as anything in turfs - visibleTurfs) var/image/new_static = turfs[obscured_turf] active_static_images += new_static obscuredTurfs[obscured_turf] = new_static - -#undef UPDATE_BUFFER_TIME - -GLOBAL_VAR_INIT(block_camera_updates, FALSE) - -ADMIN_VERB(pause_camera_updates, R_ADMIN, "Toggle Camera Updates", "Stop security cameras from updating, meaning what they see now is what they will see forever.", ADMIN_CATEGORY_DEBUG) - GLOB.block_camera_updates = !GLOB.block_camera_updates diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 900ff158ee7..6d279194f8f 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -221,7 +221,7 @@ /mob/eye/camera/ai/Hear(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods = list(), message_range) . = ..() - if(relay_speech && speaker && ai && !radio_freq && speaker != ai && GLOB.cameranet.checkCameraVis(speaker)) + if(relay_speech && speaker && ai && !radio_freq && speaker != ai && SScameras.is_visible_by_cameras(speaker)) ai.relay_speech(speaker, message_language, raw_message, radio_freq, spans, message_mods) /obj/effect/overlay/ai_detect_hud diff --git a/code/modules/mob/living/silicon/silicon_movement.dm b/code/modules/mob/living/silicon/silicon_movement.dm index 0ea6ece169c..7ead122301b 100644 --- a/code/modules/mob/living/silicon/silicon_movement.dm +++ b/code/modules/mob/living/silicon/silicon_movement.dm @@ -19,6 +19,6 @@ */ /mob/living/silicon/proc/do_camera_update(oldLoc) if(oldLoc != get_turf(src)) - GLOB.cameranet.updatePortableCamera(builtInCamera, SILICON_CAMERA_BUFFER) + SScameras.update_portable_camera(builtInCamera, SILICON_CAMERA_BUFFER) updating = FALSE #undef SILICON_CAMERA_BUFFER diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index 4a90f25f5b0..51e3cfed303 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -129,7 +129,7 @@ data["network"] = network data["mapRef"] = cam_screen.assigned_map data["can_spy"] = !!spying - data["cameras"] = GLOB.cameranet.get_available_cameras_data(network) + data["cameras"] = SScameras.get_available_cameras_data(network) return data /datum/computer_file/program/secureye/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) @@ -145,7 +145,7 @@ if(!spying) playsound(computer, SFX_TERMINAL_TYPE, 25, FALSE) - var/obj/machinery/camera/selected_camera = locate(params["camera"]) in GLOB.cameranet.cameras + var/obj/machinery/camera/selected_camera = locate(params["camera"]) in SScameras.cameras if(selected_camera) camera_ref = WEAKREF(selected_camera) else @@ -168,12 +168,13 @@ /datum/computer_file/program/secureye/proc/on_track_target(datum/trackable/source, mob/living/target) SIGNAL_HANDLER - var/datum/camerachunk/target_camerachunk = GLOB.cameranet.getTurfVis(get_turf(target)) + var/target_turf = get_turf(target) + 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]"]) - var/found_target = locate(target) in cameras.can_see() - if(!found_target) + 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(!(target_turf in cameras.can_see())) continue var/new_camera = WEAKREF(cameras) if(camera_ref == new_camera) diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 9ef40666fc3..c0c956e3698 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -191,17 +191,11 @@ /// Check whether an AI could take a picture of the target turf. /obj/item/camera/proc/can_ai_target(turf/target_turf) - if(!GLOB.cameranet.checkTurfVis(target_turf)) - return FALSE - return TRUE + return SScameras.is_visible_by_cameras(target_turf) /// Check whether a mob could take a picture of the target turf. /obj/item/camera/proc/can_mob_target(turf/target_turf, mob/user) - var/user_view = user.client ? user.client.view : WIDESCREEN_VIEWPORT_SIZE - var/user_eye = user.client ? user.client.eye : user - if(!(target_turf in get_hear(user_view, user_eye))) - return FALSE - return TRUE + return (target_turf in get_hear_turfs(user.client?.view || world.view, user.client?.eye || user)) /obj/item/camera/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) // Always skip on storage and tables @@ -260,18 +254,17 @@ var/list/desc = list("This is a photo of an area of [size_x+1] meters by [size_y+1] meters.") var/list/mobs_spotted = list() var/list/dead_spotted = list() - var/list/seen - var/list/viewlist = user?.client ? getviewsize(user.client.view) : getviewsize(world.view) - var/viewr = max(viewlist[1], viewlist[2]) + max(size_x, size_y) - var/viewc = user?.client ? user.client.eye : target - seen = get_hear(viewr, viewc) + var/list/viewlist = getviewsize(user?.client?.view || world.view) + var/view_range = max(viewlist[1], viewlist[2]) + max(size_x, size_y) + var/viewer = user?.client?.eye || user || target // not sure why target is a fallback + var/list/seen = get_hear_turfs(view_range, viewer) var/list/turfs = list() var/list/mobs = list() var/blueprints = FALSE var/clone_area = SSmapping.request_turf_block_reservation(size_x * 2 + 1, size_y * 2 + 1, 1) ///list of human names taken on picture var/list/names = list() - var/cameranet_user = isAI(user) || istype(viewc, /mob/eye/camera) + var/cameranet_user = isAI(user) || istype(viewer, /mob/eye/camera) var/width = size_x * 2 + 1 var/height = size_y * 2 + 1 @@ -279,7 +272,7 @@ if(isnull(seen_placeholder)) continue - if(cameranet_user && !GLOB.cameranet.checkTurfVis(seen_placeholder)) + if(cameranet_user && !SScameras.is_visible_by_cameras(seen_placeholder)) continue if(!cameranet_user && !(seen_placeholder in seen)) continue diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 960fa43a61c..ffe23c8e5b4 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -199,7 +199,7 @@ /// Validates whether the target turf can be interacted with. /obj/machinery/computer/camera_advanced/xenobio/proc/validate_turf(mob/living/user, turf/open/target_turf) - if(!GLOB.cameranet.checkTurfVis(target_turf)) + if(!SScameras.is_visible_by_cameras(target_turf)) target_turf.balloon_alert(user, "outside of view!") return FALSE diff --git a/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm b/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm index 89b20e7adbc..9f9220c3f8d 100644 --- a/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm +++ b/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm @@ -238,11 +238,11 @@ All ShuttleMove procs go here . = ..() if(. & MOVE_AREA) . |= MOVE_CONTENTS - GLOB.cameranet.removeCamera(src) + SScameras.remove_camera_from_chunk(src) /obj/machinery/camera/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) . = ..() - GLOB.cameranet.addCamera(src) + SScameras.add_camera_to_chunk(src) /obj/machinery/mech_bay_recharge_port/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir) . = ..() diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm index 17173e79cd9..95c1e1c386f 100644 --- a/code/modules/transport/tram/tram_doors.dm +++ b/code/modules/transport/tram/tram_doors.dm @@ -54,7 +54,6 @@ set_density(FALSE) if(!isnull(filler)) filler.set_density(FALSE) - update_freelook_sight() flags_1 &= ~PREVENT_CLICK_UNDER_1 air_update_turf(TRUE, FALSE) var/open_delay = animation_segment_delay(AIRLOCK_OPENING_FINISHED) - passable_delay @@ -113,7 +112,6 @@ set_density(TRUE) if(!isnull(filler)) filler.set_density(TRUE) - update_freelook_sight() flags_1 |= PREVENT_CLICK_UNDER_1 air_update_turf(TRUE, TRUE) crush() diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index b5817d81378..46b49cc2ee5 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -205,6 +205,6 @@ */ /obj/vehicle/sealed/mecha/proc/do_camera_update(oldLoc) if(oldLoc != get_turf(src)) - GLOB.cameranet.updatePortableCamera(chassis_camera, MECH_CAMERA_BUFFER) + SScameras.update_portable_camera(chassis_camera, MECH_CAMERA_BUFFER) updating = FALSE #undef MECH_CAMERA_BUFFER diff --git a/code/modules/wiremod/components/atom/remotecam.dm b/code/modules/wiremod/components/atom/remotecam.dm index bbbab6043af..070d164c01c 100644 --- a/code/modules/wiremod/components/atom/remotecam.dm +++ b/code/modules/wiremod/components/atom/remotecam.dm @@ -189,7 +189,7 @@ /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) - GLOB.cameranet.updatePortableCamera(shell_camera, 0.5 SECONDS) + SScameras.update_portable_camera(shell_camera, 0.5 SECONDS) /** * Add camera from global cameranet @@ -197,8 +197,8 @@ /obj/item/circuit_component/remotecam/proc/cameranet_add() if(current_cameranet_state) return - GLOB.cameranet.cameras += shell_camera - GLOB.cameranet.addCamera(shell_camera) + SScameras.cameras += shell_camera + SScameras.add_camera_to_chunk(shell_camera) current_cameranet_state = TRUE /** @@ -207,8 +207,8 @@ /obj/item/circuit_component/remotecam/proc/cameranet_remove() if(!current_cameranet_state) return - GLOB.cameranet.removeCamera(shell_camera) - GLOB.cameranet.cameras -= shell_camera + SScameras.remove_camera_from_chunk(shell_camera) + SScameras.cameras -= shell_camera current_cameranet_state = FALSE /** diff --git a/tgstation.dme b/tgstation.dme index 874f9bd1cad..1343a9f44b0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -675,6 +675,7 @@ #include "code\controllers\subsystem\ban_cache.dm" #include "code\controllers\subsystem\blackbox.dm" #include "code\controllers\subsystem\blood_drying.dm" +#include "code\controllers\subsystem\cameras.dm" #include "code\controllers\subsystem\chat.dm" #include "code\controllers\subsystem\dbcore.dm" #include "code\controllers\subsystem\dcs.dm" @@ -5520,7 +5521,6 @@ #include "code\modules\mob\living\silicon\ai\robot_control.dm" #include "code\modules\mob\living\silicon\ai\vox_sounds.dm" #include "code\modules\mob\living\silicon\ai\ai_actions\remote_power.dm" -#include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm" #include "code\modules\mob\living\silicon\ai\freelook\chunk.dm" #include "code\modules\mob\living\silicon\ai\freelook\eye.dm" #include "code\modules\mob\living\silicon\robot\death.dm"