// CAMERA CHUNK // // A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. // Allows the Eye to stream these chunks and know what it can and cannot see. #define UPDATE_BUFFER 25 // 2.5 seconds // CHUNK // // A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. // Allows the Eye to stream these chunks and know what it can and cannot see. /datum/obfuscation var/icon = 'icons/effects/cameravis.dmi' var/icon_state = "black" var/list/obfuscation_images = list() var/static/icon/obfuscation_underlay // There is an exploit were clients can memory-edit their local version of the static images, allowing them to see everything. This is a minor attempt to make that more difficult. /datum/obfuscation/Destroy() obfuscation_images.Cut() . = ..() /datum/obfuscation/proc/has_obfuscation(var/turf/T) return !isnull(obfuscation_images[T]) /datum/obfuscation/proc/get_obfuscation(var/turf/T) var/image/obfuscation = obfuscation_images[T] if(!obfuscation) obfuscation = image(icon, T, icon_state) obfuscation.layer = OBFUSCATION_LAYER obfuscation.plane = GAME_PLANE if(!obfuscation_underlay) // Creating a new icon of a fairly common icon state, adding some random color to prevent address searching, and hoping being static kills memory locality var/turf/floor = /turf/simulated/floor/tiled obfuscation_underlay = icon(initial(floor.icon), initial(floor.icon_state)) obfuscation_underlay.Blend(rgb(rand(0,255),rand(0,255),rand(0,255))) obfuscation.underlays += obfuscation_underlay obfuscation_images[T] = obfuscation return obfuscation /datum/chunk var/datum/visualnet/visualnet var/list/obscuredTurfs = list() var/list/visibleTurfs = list() var/list/obscured = list() var/list/turfs = list() var/list/seenby = list() var/list/sources = list() var/dirty = FALSE var/updating = FALSE var/x = 0 var/y = 0 var/z = 0 var/datum/obfuscation/obfuscation = new() // Create a new camera chunk, since the chunks are made as they are needed. /datum/chunk/New(var/datum/visualnet/visualnet, x, y, z) ..() src.visualnet = visualnet // 0xf = 15 x &= ~0xf y &= ~0xf src.x = x src.y = y src.z = z var/turf/center = locate(x + 8, y + 8, z) for(var/turf/t in RANGE_TURFS(10, center)) if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16) turfs[t] = t add_sources(visualnet.sources) acquire_visible_turfs(visibleTurfs) // Removes turf that isn't in turfs. visibleTurfs &= turfs obscuredTurfs = turfs - visibleTurfs for(var/turf in obscuredTurfs) var/turf/t = turf obscured += obfuscation.get_obfuscation(t) /datum/chunk/Destroy() visualnet = null . = ..() /datum/chunk/proc/add_sources(var/list/sources) var/turf/center = locate(x + 8, y + 8, z) for(var/entry in sources) var/atom/A = entry if(get_dist(get_turf(A), center) > 16) continue add_source(A) // The visualnet checks if a source already exists or not, as appropriate, before calling add/remove_source on the chunk /datum/chunk/proc/add_source(var/atom/source) if(source in sources) return FALSE sources += source visibility_changed() return TRUE /datum/chunk/proc/remove_source(var/atom/source) if(sources.Remove(source)) visibility_changed() return TRUE return FALSE // Visualnet adds and removes eyes. /datum/chunk/proc/add_eye(mob/abstract/eye/freelook/eye) seenby += eye eye.visibleChunks += src if(eye.owner && eye.owner.client) eye.owner.client.images += obscured /datum/chunk/proc/remove_eye(mob/abstract/eye/freelook/eye) seenby -= eye eye.visibleChunks -= src if(eye.owner && eye.owner.client) eye.owner.client.images -= obscured // 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. /datum/chunk/proc/visibility_changed(var/update_now = FALSE) if(update_now) update(TRUE) return if(updating) return if(seenby.len) updating = TRUE addtimer(CALLBACK(src, PROC_REF(update)), UPDATE_BUFFER) else dirty = TRUE // The actual updating. /datum/chunk/proc/update(var/forced = FALSE) if(!updating && !forced) return var/list/newVisibleTurfs = new() acquire_visible_turfs(newVisibleTurfs) // Removes turf that isn't in turfs. newVisibleTurfs &= turfs var/list/visAdded = newVisibleTurfs - visibleTurfs var/list/visRemoved = visibleTurfs - newVisibleTurfs visibleTurfs = newVisibleTurfs obscuredTurfs = turfs - newVisibleTurfs for(var/turf in visAdded) var/turf/t = turf if(obfuscation.has_obfuscation(t)) var/image/obfuscation_image = obfuscation.get_obfuscation(t) obscured -= obfuscation_image for(var/eye in seenby) var/mob/abstract/eye/m = eye if (m && m.owner && m.owner.client) m.owner.client.images -= obfuscation_image for(var/turf in visRemoved) var/turf/t = turf if(obscuredTurfs[t]) var/image/obfuscation_image = obfuscation.get_obfuscation(t) obscured += obfuscation_image for(var/eye in seenby) var/mob/abstract/eye/m = eye if (m && m.owner && m.owner.client) m.owner.client.images += obfuscation_image dirty = FALSE updating = FALSE /datum/chunk/proc/acquire_visible_turfs(var/list/visible) return /proc/seen_turfs_in_range(var/source, var/range) . = list() var/turf/pos = get_turf(source) if(pos) for(var/turf/T in get_hear(range, pos)) . += T #undef UPDATE_BUFFER