mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 21:48:21 +01:00
Camera net/chunk refactor. Slight performance improvements and makes it GC properly (#20302)
* Add SScamera * Refactor camera * Refactor how camera chunks add/remove cams * Use CAMERA_VIEW_DISTANCE to determine max view dist of cam * Fix movable cameras and optimise them * Optimise update() * Ensure aiEyes get removed properly when deleted * Final optimisations and refactoring * Fix cameras being EMPed * Shits fixed * AA review * Fix merge mistake * Add comment about early return * Seans review * the it the Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> * Update code/game/machinery/camera/camera.dm Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com> * Ensure the robit has a camera before updating it --------- Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> Co-authored-by: Charlie <69320440+hal9000PR@users.noreply.github.com> Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>
This commit is contained in:
co-authored by
S34N
Ryan
Charlie
parent
4a1873023a
commit
0fedbb9257
@@ -37,9 +37,8 @@
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/ert/proc/register_camera(mob/wearer)
|
||||
if(camera || !has_camera)
|
||||
return
|
||||
camera = new /obj/machinery/camera/portable(src)
|
||||
camera = new /obj/machinery/camera/portable(src, FALSE)
|
||||
camera.network = list("ERT")
|
||||
GLOB.cameranet.removeCamera(camera)
|
||||
camera.c_tag = wearer.name
|
||||
to_chat(wearer, "<span class='notice'>User scanned as [camera.c_tag]. Camera activated.</span>")
|
||||
|
||||
|
||||
@@ -1222,7 +1222,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/list/obj/machinery/camera/remove = list()
|
||||
var/list/obj/machinery/camera/visible = list()
|
||||
for(var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
|
||||
for(var/obj/machinery/camera/C in CC.cameras)
|
||||
for(var/obj/machinery/camera/C in CC.active_cameras)
|
||||
if(!C.can_use() || get_dist(C, eyeobj) > 7)
|
||||
continue
|
||||
visible |= C
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// CAMERA NET
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
|
||||
#define CHUNK_SIZE 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
|
||||
|
||||
GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
|
||||
/datum/cameranet
|
||||
@@ -20,16 +17,16 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
|
||||
// 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 &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new /datum/camerachunk(null, x, y, z)
|
||||
@@ -55,15 +52,15 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
chunks_pre_seen |= eye.visibleCameraChunks
|
||||
// 0xf = 15
|
||||
var/static_range = eye.static_visibility_range
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CHUNK_SIZE - 1)
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
visibleChunks |= getCameraChunk(x, y, eye.z)
|
||||
|
||||
var/list/remove = eye.visibleCameraChunks - visibleChunks
|
||||
@@ -115,22 +112,17 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
// Removes a camera from a chunk.
|
||||
|
||||
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 0)
|
||||
majorChunkChange(c, 0)
|
||||
|
||||
// Add a camera to a chunk.
|
||||
|
||||
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 1)
|
||||
majorChunkChange(c, 1)
|
||||
|
||||
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
|
||||
|
||||
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 1)
|
||||
//else
|
||||
// majorChunkChange(c, 0)
|
||||
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c, turf/old_loc)
|
||||
majorChunkChange(c, 1, old_loc)
|
||||
|
||||
// Never access this proc directly!!!!
|
||||
// This will update the chunk and all the surrounding chunks.
|
||||
@@ -138,31 +130,37 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
// 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.
|
||||
|
||||
/datum/cameranet/proc/majorChunkChange(atom/c, choice)
|
||||
/datum/cameranet/proc/majorChunkChange(atom/c, choice, turf/old_loc = null)
|
||||
// 0xf = 15
|
||||
if(!c)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
if(T)
|
||||
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
// to_chat(world, "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]")
|
||||
if(old_loc)
|
||||
// Check if the current turf falls in the same chunka as the old_loc. If so, don't do anything
|
||||
if(T.x & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.x & ~(CAMERA_CHUNK_SIZE - 1) && T.y & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.y & ~(CAMERA_CHUNK_SIZE - 1))
|
||||
return
|
||||
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
|
||||
if(choice == 0)
|
||||
// Remove the camera.
|
||||
chunk.cameras -= c
|
||||
else if(choice == 1)
|
||||
// You can't have the same camera in the list twice.
|
||||
chunk.cameras |= c
|
||||
chunk.hasChanged()
|
||||
// Use camera view distance here to actually know how far a camera can max watch
|
||||
var/x1 = max(0, T.x - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
|
||||
if(choice == 0)
|
||||
// Remove the camera.
|
||||
chunk.remove_camera(c)
|
||||
else if(choice == 1)
|
||||
// You can't have the same camera in the list twice.
|
||||
chunk.add_camera(c)
|
||||
chunk.hasChanged()
|
||||
|
||||
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define UPDATE_BUFFER 25 // 2.5 seconds
|
||||
|
||||
// CAMERA CHUNK
|
||||
//
|
||||
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
@@ -9,31 +7,68 @@
|
||||
var/list/obscuredTurfs = list()
|
||||
var/list/visibleTurfs = list()
|
||||
var/list/obscured = list()
|
||||
var/list/cameras = list()
|
||||
var/list/active_cameras = list()
|
||||
var/list/inactive_cameras = list()
|
||||
var/list/turfs = list()
|
||||
var/list/seenby = list()
|
||||
var/visible = FALSE
|
||||
var/changed = FALSE
|
||||
var/updating = FALSE
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
|
||||
// Add an AI eye to the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/add_camera(obj/machinery/camera/cam)
|
||||
if(active_cameras[cam] || inactive_cameras[cam])
|
||||
return
|
||||
// Register all even though it is active/inactive. Won't get called incorrectly
|
||||
RegisterSignal(cam, COMSIG_CAMERA_OFF, PROC_REF(deactivate_camera))
|
||||
RegisterSignal(cam, COMSIG_CAMERA_ON, PROC_REF(activate_camera))
|
||||
RegisterSignal(cam, COMSIG_PARENT_QDELETING, PROC_REF(remove_camera))
|
||||
RegisterSignal(cam, COMSIG_CAMERA_MOVED, PROC_REF(camera_moved))
|
||||
if(cam.can_use())
|
||||
active_cameras[cam] = cam
|
||||
else
|
||||
inactive_cameras[cam] = cam
|
||||
|
||||
/datum/camerachunk/proc/camera_moved(obj/machinery/camera/cam, atom/old_loc)
|
||||
var/turf/T = get_turf(cam)
|
||||
|
||||
// Falls outside of the chunk view distance
|
||||
if(T.x + CAMERA_VIEW_DISTANCE < x || T.x - CAMERA_VIEW_DISTANCE >= x + CAMERA_CHUNK_SIZE || T.y + CAMERA_VIEW_DISTANCE < y || T.y - CAMERA_VIEW_DISTANCE >= y + CAMERA_CHUNK_SIZE || T.z != z)
|
||||
remove_camera(cam)
|
||||
|
||||
/datum/camerachunk/proc/remove_camera(obj/machinery/camera/cam)
|
||||
UnregisterSignal(cam, list(COMSIG_CAMERA_OFF, COMSIG_CAMERA_ON, COMSIG_PARENT_QDELETING, COMSIG_CAMERA_MOVED))
|
||||
active_cameras -= cam
|
||||
inactive_cameras -= cam
|
||||
SScamera.queue(src)
|
||||
|
||||
/datum/camerachunk/proc/activate_camera(obj/machinery/camera/cam)
|
||||
inactive_cameras -= cam
|
||||
active_cameras += cam
|
||||
SScamera.queue(src)
|
||||
|
||||
/datum/camerachunk/proc/deactivate_camera(obj/machinery/camera/cam)
|
||||
inactive_cameras += cam
|
||||
active_cameras -= cam
|
||||
SScamera.queue(src)
|
||||
|
||||
// Add an AI eye to the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/add(mob/camera/aiEye/eye, add_images = TRUE)
|
||||
if(add_images)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
if(client)
|
||||
client.images += obscured
|
||||
eye.visibleCameraChunks += src
|
||||
visible++
|
||||
seenby += eye
|
||||
RegisterSignal(eye, COMSIG_PARENT_QDELETING, PROC_REF(aiEye_destroyed))
|
||||
if(changed)
|
||||
update()
|
||||
SScamera.queue(src)
|
||||
|
||||
/datum/camerachunk/proc/aiEye_destroyed(mob/camera/aiEye/eye)
|
||||
remove(eye, FALSE)
|
||||
|
||||
// Remove an AI eye from the chunk, then update if changed.
|
||||
|
||||
/datum/camerachunk/proc/remove(mob/camera/aiEye/eye, remove_images = TRUE)
|
||||
if(remove_images)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
@@ -41,8 +76,7 @@
|
||||
client.images -= obscured
|
||||
eye.visibleCameraChunks -= src
|
||||
seenby -= eye
|
||||
if(visible > 0)
|
||||
visible--
|
||||
UnregisterSignal(eye, COMSIG_PARENT_QDELETING)
|
||||
|
||||
// Called when a chunk has changed. I.E: A wall was deleted.
|
||||
|
||||
@@ -55,12 +89,12 @@
|
||||
// instead be flagged to update the next time an AI Eye moves near it.
|
||||
|
||||
/datum/camerachunk/proc/hasChanged(update_now = 0)
|
||||
if(visible || update_now)
|
||||
if(!updating)
|
||||
updating = TRUE
|
||||
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
|
||||
update()
|
||||
updating = FALSE
|
||||
if(update_now)
|
||||
update()
|
||||
SScamera.remove_from_queue(src)
|
||||
|
||||
if(length(seenby))
|
||||
SScamera.queue(src)
|
||||
else
|
||||
changed = TRUE
|
||||
|
||||
@@ -69,106 +103,69 @@
|
||||
/datum/camerachunk/proc/update()
|
||||
var/list/newVisibleTurfs = list()
|
||||
|
||||
for(var/camera in cameras)
|
||||
var/obj/machinery/camera/c = camera
|
||||
|
||||
if(!c)
|
||||
continue
|
||||
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
|
||||
if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
|
||||
continue
|
||||
for(var/obj/machinery/camera/c as anything in active_cameras)
|
||||
var/turf/point = locate(src.x + (CAMERA_CHUNK_SIZE / 2), src.y + (CAMERA_CHUNK_SIZE / 2), src.z)
|
||||
var/turf/T = get_turf(c)
|
||||
if(get_dist(point, T) > CAMERA_VIEW_DISTANCE + (CAMERA_CHUNK_SIZE / 2))
|
||||
continue // Still needed for Ais who get created on Z level 1 on the spot of the new player
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
newVisibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
newVisibleTurfs &= turfs
|
||||
if(turfs[t])
|
||||
newVisibleTurfs[t] = t
|
||||
|
||||
var/list/visAdded = newVisibleTurfs - visibleTurfs
|
||||
var/list/visRemoved = visibleTurfs - newVisibleTurfs
|
||||
|
||||
visibleTurfs = newVisibleTurfs
|
||||
obscuredTurfs = turfs - newVisibleTurfs
|
||||
|
||||
for(var/turf in visAdded)
|
||||
var/turf/t = turf
|
||||
var/list/images_to_remove = list()
|
||||
var/list/images_to_add = list()
|
||||
for(var/turf/t as anything in visAdded)
|
||||
if(t.obscured)
|
||||
obscured -= t.obscured
|
||||
for(var/eye in seenby)
|
||||
var/mob/camera/aiEye/m = eye
|
||||
if(!m)
|
||||
continue
|
||||
var/client/client = m.GetViewerClient()
|
||||
if(client)
|
||||
client.images -= t.obscured
|
||||
images_to_remove += t.obscured
|
||||
|
||||
for(var/turf in visRemoved)
|
||||
var/turf/t = turf
|
||||
if(obscuredTurfs[t])
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, null, BYOND_LIGHTING_LAYER + 0.1)
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
for(var/turf/t as anything in visRemoved)
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, null, BYOND_LIGHTING_LAYER + 0.1)
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
obscured += t.obscured
|
||||
images_to_add += t.obscured
|
||||
|
||||
obscured += t.obscured
|
||||
for(var/eye in seenby)
|
||||
var/mob/camera/aiEye/m = eye
|
||||
if(!m)
|
||||
seenby -= m
|
||||
continue
|
||||
var/client/client = m.GetViewerClient()
|
||||
if(client)
|
||||
client.images += t.obscured
|
||||
for(var/mob/camera/aiEye/eye as anything in seenby)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
if(client)
|
||||
client.images -= images_to_remove
|
||||
client.images += images_to_add
|
||||
changed = FALSE
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
|
||||
/datum/camerachunk/New(loc, x, y, z)
|
||||
|
||||
// 0xf = 15
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
|
||||
for(var/obj/machinery/camera/c in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
|
||||
if(c.can_use())
|
||||
cameras += c
|
||||
var/half_chunk = CAMERA_CHUNK_SIZE / 2
|
||||
for(var/obj/machinery/camera/c in urange(half_chunk + CAMERA_VIEW_DISTANCE, locate(x + half_chunk, y + half_chunk, z)))
|
||||
add_camera(c)
|
||||
|
||||
for(var/turf/t in block(locate(max(x, 1), max(y, 1), max(z, 1)), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
|
||||
for(var/turf/t in block(locate(max(x, 1), max(y, 1), max(z, 1)), locate(min(x + CAMERA_CHUNK_SIZE - 1, world.maxx), min(y + CAMERA_CHUNK_SIZE - 1, world.maxy), z)))
|
||||
turfs[t] = t
|
||||
|
||||
for(var/camera in cameras)
|
||||
var/obj/machinery/camera/c = camera
|
||||
if(!c)
|
||||
continue
|
||||
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
for(var/obj/machinery/camera/c as anything in active_cameras)
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
visibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
visibleTurfs &= turfs
|
||||
if(turfs[t])
|
||||
visibleTurfs[t] = t
|
||||
|
||||
obscuredTurfs = turfs - visibleTurfs
|
||||
|
||||
for(var/turf in obscuredTurfs)
|
||||
var/turf/t = turf
|
||||
for(var/turf/t as anything in obscuredTurfs)
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, "black", BYOND_LIGHTING_LAYER + 0.1)
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
obscured += t.obscured
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
|
||||
@@ -99,7 +99,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/lamp_intensity = 0 //Luminosity of the headlamp. 0 is off. Higher settings than the minimum require power.
|
||||
var/lamp_recharging = FALSE //Flag for if the lamp is on cooldown after being forcibly disabled.
|
||||
|
||||
var/updating = FALSE //portable camera camerachunk update
|
||||
/// When the camera moved signal was send last. Avoid overdoing it
|
||||
var/last_camera_update
|
||||
|
||||
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
|
||||
|
||||
@@ -1225,19 +1226,16 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
cell = null
|
||||
qdel(src)
|
||||
|
||||
#define BORG_CAMERA_BUFFER 3 SECONDS
|
||||
#define CAMERA_UPDATE_COOLDOWN 2.5 SECONDS
|
||||
|
||||
/mob/living/silicon/robot/Move(atom/newloc, direct, movetime)
|
||||
var/oldLoc = loc
|
||||
/mob/living/silicon/robot/Moved(atom/OldLoc, Dir, Forced)
|
||||
. = ..()
|
||||
if(. && !updating && camera)
|
||||
updating = TRUE
|
||||
spawn(BORG_CAMERA_BUFFER)
|
||||
if(camera && oldLoc != loc)
|
||||
GLOB.cameranet.updatePortableCamera(camera)
|
||||
updating = FALSE
|
||||
if(camera && last_camera_update + CAMERA_UPDATE_COOLDOWN < world.time)
|
||||
last_camera_update = world.time
|
||||
GLOB.cameranet.updatePortableCamera(camera, OldLoc)
|
||||
SEND_SIGNAL(camera, COMSIG_CAMERA_MOVED, OldLoc)
|
||||
|
||||
#undef BORG_CAMERA_BUFFER
|
||||
#undef CAMERA_UPDATE_COOLDOWN
|
||||
|
||||
/mob/living/silicon/robot/proc/self_destruct()
|
||||
if(emagged)
|
||||
|
||||
Reference in New Issue
Block a user