diff --git a/code/datums/cache/air_alarm.dm b/code/datums/cache/air_alarm.dm
new file mode 100644
index 00000000000..07caea0f3ad
--- /dev/null
+++ b/code/datums/cache/air_alarm.dm
@@ -0,0 +1,27 @@
+var/global/datum/repository/air_alarm/air_alarm_repository = new()
+
+/datum/repository/air_alarm/proc/air_alarm_data(var/list/monitored_alarms, var/refresh = 0, var/obj/machinery/alarm/passed_alarm)
+ var/alarms[0]
+
+ var/datum/cache_entry/cache_entry = cache_data
+ if(!cache_entry)
+ cache_entry = new/datum/cache_entry
+ cache_data = cache_entry
+
+ if(!refresh)
+ return cache_entry.data
+
+ if(ticker && ticker.current_state < GAME_STATE_PLAYING && istype(passed_alarm)) // Generating the list for the first time as the game hasn't started - no need to run through the machines list everything every time
+ alarms[++alarms.len] = passed_alarm.get_nano_data_console()
+ else
+ for(var/obj/machinery/alarm/alarm in sortAtom((monitored_alarms ? monitored_alarms : machines)))
+ if(!monitored_alarms && alarm.z != ZLEVEL_STATION && alarm.z != ZLEVEL_ASTEROID)
+ continue
+ alarms[++alarms.len] = alarm.get_nano_data_console()
+
+ cache_entry.timestamp = world.time //+ 10 SECONDS
+ cache_entry.data = alarms
+ return alarms
+
+/datum/repository/air_alarm/proc/update_cache(var/obj/machinery/alarm/alarm)
+ return air_alarm_data(refresh = 1, passed_alarm = alarm)
\ No newline at end of file
diff --git a/code/datums/cache/apc.dm b/code/datums/cache/apc.dm
new file mode 100644
index 00000000000..e6dc996827b
--- /dev/null
+++ b/code/datums/cache/apc.dm
@@ -0,0 +1,28 @@
+var/global/datum/repository/apc/apc_repository = new()
+
+/datum/repository/apc/proc/apc_data(var/obj/machinery/computer/monitor/powermonitor)
+ var/apcData[0]
+
+ var/datum/cache_entry/cache_entry = cache_data
+ if(!cache_entry)
+ cache_entry = new/datum/cache_entry
+ cache_data = cache_entry
+
+ if(world.time < cache_entry.timestamp)
+ return cache_entry.data
+
+ if (powermonitor && !isnull(powermonitor.powernet))
+ var/list/L = list()
+ for(var/obj/machinery/power/terminal/term in powermonitor.powernet.nodes)
+ if(istype(term.master, /obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = term.master
+ L += A
+
+ var/list/Status = list(0,0,1,1) // Status: off, auto-off, on, auto-on
+ var/list/chg = list(0,1,1) // Charging: no, charging, full
+ for(var/obj/machinery/power/apc/A in L)
+ apcData[++apcData.len] = list("Name" = html_encode(A.area.name), "Equipment" = Status[A.equipment+1], "Lights" = Status[A.lighting+1], "Environment" = Status[A.environ+1], "CellPct" = A.cell ? round(A.cell.percent(),1) : -1, "CellStatus" = A.cell ? chg[A.charging+1] : 0)
+
+ cache_entry.timestamp = world.time + 5 SECONDS
+ cache_entry.data = apcData
+ return apcData
\ No newline at end of file
diff --git a/code/datums/cache/cache.dm b/code/datums/cache/cache.dm
new file mode 100644
index 00000000000..2502bb871b2
--- /dev/null
+++ b/code/datums/cache/cache.dm
@@ -0,0 +1,6 @@
+/datum/cache_entry
+ var/timestamp
+ var/data
+
+/datum/repository
+ var/cache_data
\ No newline at end of file
diff --git a/code/datums/cache/crew.dm b/code/datums/cache/crew.dm
new file mode 100644
index 00000000000..0afb70a4404
--- /dev/null
+++ b/code/datums/cache/crew.dm
@@ -0,0 +1,67 @@
+var/global/datum/repository/crew/crew_repository = new()
+
+/datum/repository/crew/New()
+ cache_data = list()
+ ..()
+
+/datum/repository/crew/proc/health_data(var/turf/T)
+ var/list/crewmembers = list()
+ if(!T)
+ return crewmembers
+
+ var/z_level = "[T.z]"
+ var/datum/cache_entry/cache_entry = cache_data[z_level]
+ if(!cache_entry)
+ cache_entry = new/datum/cache_entry
+ cache_data[z_level] = cache_entry
+
+ if(world.time < cache_entry.timestamp)
+ return cache_entry.data
+
+ var/tracked = scan()
+ for(var/obj/item/clothing/under/C in tracked)
+ var/turf/pos = get_turf(C)
+ if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
+ if(istype(C.loc, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = C.loc
+ if(H.w_uniform != C)
+ continue
+
+ var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
+
+ crewmemberData["sensor_type"] = C.sensor_mode
+ crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
+ crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
+ crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
+
+ if(C.sensor_mode >= SUIT_SENSOR_BINARY)
+ crewmemberData["dead"] = H.stat > UNCONSCIOUS
+
+ if(C.sensor_mode >= SUIT_SENSOR_VITAL)
+ crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
+ crewmemberData["tox"] = round(H.getToxLoss(), 1)
+ crewmemberData["fire"] = round(H.getFireLoss(), 1)
+ crewmemberData["brute"] = round(H.getBruteLoss(), 1)
+
+ if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
+ var/area/A = get_area(H)
+ crewmemberData["area"] = sanitize(A.name)
+ crewmemberData["x"] = pos.x
+ crewmemberData["y"] = pos.y
+
+ crewmembers[++crewmembers.len] = crewmemberData
+
+ crewmembers = sortByKey(crewmembers, "name")
+ cache_entry.timestamp = world.time + 5 SECONDS
+ cache_entry.data = crewmembers
+
+ return crewmembers
+
+/datum/repository/crew/proc/scan()
+ var/list/tracked = list()
+ for(var/mob/living/carbon/human/H in mob_list)
+ if(istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/C = H.w_uniform
+ if (C.has_sensor)
+ tracked |= C
+ return tracked
diff --git a/code/datums/cache/powermonitor.dm b/code/datums/cache/powermonitor.dm
new file mode 100644
index 00000000000..a99b380a13d
--- /dev/null
+++ b/code/datums/cache/powermonitor.dm
@@ -0,0 +1,24 @@
+var/global/datum/repository/powermonitor/powermonitor_repository = new()
+
+/datum/repository/powermonitor/proc/powermonitor_data(var/refresh = 0)
+ var/pMonData[0]
+
+ var/datum/cache_entry/cache_entry = cache_data
+ if(!cache_entry)
+ cache_entry = new/datum/cache_entry
+ cache_data = cache_entry
+
+ if(!refresh)
+ return cache_entry.data
+
+ for(var/obj/machinery/computer/monitor/pMon in machines)
+ if( !(pMon.stat & (NOPOWER|BROKEN)) )
+ pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]")
+
+ cache_entry.timestamp = world.time //+ 30 SECONDS
+ cache_entry.data = pMonData
+ return pMonData
+
+/datum/repository/powermonitor/proc/update_cache()
+ return powermonitor_data(refresh = 1)
+
\ No newline at end of file
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 1a9dcca511e..7dafb778e7a 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -66,8 +66,10 @@
atmosalm = danger_level
for (var/obj/machinery/alarm/AA in src)
AA.update_icon()
-
+
+ air_alarm_repository.update_cache(src)
return 1
+ air_alarm_repository.update_cache(src)
return 0
/area/proc/air_doors_close()
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index f5ef29300f8..824fd231180 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -204,6 +204,10 @@
/obj/machinery/alarm/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
+
+ if (src in machines) // So the cache can properly update
+ removeAtProcessing()
+ air_alarm_repository.update_cache(src)
return ..()
/obj/machinery/alarm/proc/first_run()
@@ -212,6 +216,7 @@
if (name == "alarm")
name = "[alarm_area.name] Air Alarm"
apply_preset(1) // Don't cycle.
+ air_alarm_repository.update_cache(src)
/obj/machinery/alarm/initialize()
set_frequency(frequency)
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 58fb54bdfde..cc192ec8c53 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -193,6 +193,7 @@
src.scan_mob(src.scanner.occupant)
loading = 0
+ nanomanager.update_uis(src)
if(href_list["task"])
switch(href_list["task"])
@@ -245,10 +246,12 @@
if("load")
if ((isnull(src.diskette)) || isnull(src.diskette.buf))
src.temp = "Error: The disk's data could not be read."
+ nanomanager.update_uis(src)
return
if (isnull(src.active_record))
src.temp = "Error: No active record was found."
src.menu = 1
+ nanomanager.update_uis(src)
return
src.active_record = src.diskette.buf
diff --git a/code/game/machinery/computer/power.dm b/code/game/machinery/computer/power.dm
index b37437e7c22..50a37483526 100644
--- a/code/game/machinery/computer/power.dm
+++ b/code/game/machinery/computer/power.dm
@@ -12,10 +12,20 @@
var/datum/nano_module/power_monitor/power_monitor
/obj/machinery/computer/monitor/New()
+ ..()
power_monitor = new(src)
powernet = find_powernet()
-
+ powermonitor_repository.update_cache()
+
+/obj/machinery/computer/monitor/Destroy()
+ if (src in machines) // So the cache can properly update
+ removeAtProcessing()
+ powermonitor_repository.update_cache()
+ return ..()
+
+/obj/machinery/computer/monitor/power_change()
..()
+ powermonitor_repository.update_cache()
/obj/machinery/computer/monitor/process()
if(!powernet)
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 4e6c9c3f2ef..4b69fd2dd6d 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -282,32 +282,14 @@
/* Power Monitor (Mode: 43 / 433) */
- if(mode==43 || mode==433)
- var/pMonData[0]
- var/apcData[0]
- for(var/obj/machinery/computer/monitor/pMon in world)
- if(!(pMon.stat & (NOPOWER|BROKEN)) )
- pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]")
- if(isnull(powmonitor)) powmonitor = pMon
-
- values["powermonitors"] = pMonData
+ if(mode==43 || mode==433)
+ values["powermonitors"] = powermonitor_repository.powermonitor_data()
- if (!isnull(powmonitor.powernet))
+ if (powmonitor && !isnull(powmonitor.powernet))
values["powerconnected"] = 1
values["poweravail"] = powmonitor.powernet.avail
values["powerload"] = num2text(powmonitor.powernet.viewload,10)
- var/list/L = list()
- for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes)
- if(istype(term.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = term.master
- L += A
-
- var/list/Status = list(0,0,1,1) // Status: off, auto-off, on, auto-on
- var/list/chg = list(0,1,1) // Charging: nope, charging, full
- for(var/obj/machinery/power/apc/A in L)
- apcData[++apcData.len] = list("Name" = html_encode(A.area.name), "Equipment" = Status[A.equipment+1], "Lights" = Status[A.lighting+1], "Environment" = Status[A.environ+1], "CellPct" = A.cell ? round(A.cell.percent(),1) : -1, "CellStatus" = A.cell ? chg[A.charging+1] : 0)
-
- values["apcs"] = apcData
+ values["apcs"] = apc_repository.apc_data(powmonitor)
else
values["powerconnected"] = 0
diff --git a/code/modules/nano/modules/atmos_control.dm b/code/modules/nano/modules/atmos_control.dm
index 1c5f3c9a932..5a12c4db8a3 100644
--- a/code/modules/nano/modules/atmos_control.dm
+++ b/code/modules/nano/modules/atmos_control.dm
@@ -31,14 +31,7 @@
/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state)
var/data[0]
- var/alarms[0]
-
- // TODO: Move these to a cache, similar to cameras
- for(var/obj/machinery/alarm/alarm in sortAtom((monitored_alarms.len ? monitored_alarms : machines)))
- if(!monitored_alarms.len && alarm.z != ZLEVEL_STATION && alarm.z != ZLEVEL_ASTEROID)
- continue
- alarms[++alarms.len] = alarm.get_nano_data_console()
- data["alarms"] = alarms
+ data["alarms"] = air_alarm_repository.air_alarm_data(monitored_alarms)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
index b43d84b04eb..6888702ea83 100644
--- a/code/modules/nano/modules/crew_monitor.dm
+++ b/code/modules/nano/modules/crew_monitor.dm
@@ -1,6 +1,5 @@
/datum/nano_module/crew_monitor
name = "Crew monitor"
- var/list/tracked = new
/datum/nano_module/crew_monitor/Topic(href, href_list)
if(..())
@@ -18,51 +17,12 @@
return 1
/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- src.scan()
var/data[0]
var/turf/T = get_turf(nano_host())
- var/list/crewmembers = list()
- for(var/obj/item/clothing/under/C in src.tracked)
-
- var/turf/pos = get_turf(C)
-
- if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
- if(istype(C.loc, /mob/living/carbon/human))
-
- var/mob/living/carbon/human/H = C.loc
- if(H.w_uniform != C)
- continue
-
- var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1)
-
- crewmemberData["reference"] = "\ref[H]"
- crewmemberData["sensor_type"] = C.sensor_mode
- crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
- crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
- crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
-
- if(C.sensor_mode >= SUIT_SENSOR_BINARY)
- crewmemberData["dead"] = H.stat > 1
-
- if(C.sensor_mode >= SUIT_SENSOR_VITAL)
- crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
- crewmemberData["tox"] = round(H.getToxLoss(), 1)
- crewmemberData["fire"] = round(H.getFireLoss(), 1)
- crewmemberData["brute"] = round(H.getBruteLoss(), 1)
-
- if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
- var/area/A = get_area(H)
- crewmemberData["area"] = sanitize(A.name)
- crewmemberData["x"] = pos.x
- crewmemberData["y"] = pos.y
-
- crewmembers[++crewmembers.len] = crewmemberData
-
- crewmembers = sortByKey(crewmembers, "name")
data["isAI"] = isAI(user)
- data["crewmembers"] = crewmembers
+ data["crewmembers"] = crew_repository.health_data(T)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
@@ -78,11 +38,4 @@
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
-
-/datum/nano_module/crew_monitor/proc/scan()
- for(var/mob/living/carbon/human/H in mob_list)
- if(istype(H.w_uniform, /obj/item/clothing/under))
- var/obj/item/clothing/under/C = H.w_uniform
- if (C.has_sensor)
- tracked |= C
- return 1
+
\ No newline at end of file
diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm
index af5f12fbba8..1bcf9bc2176 100644
--- a/code/modules/nano/modules/power_monitor.dm
+++ b/code/modules/nano/modules/power_monitor.dm
@@ -13,34 +13,20 @@
/datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
var/data[0]
- var/pMonData[0]
- var/apcData[0]
data["powermonitor"] = powermonitor
if(select_monitor)
data["select_monitor"] = 1
- for(var/obj/machinery/computer/monitor/pMon in world)
- if( !(pMon.stat & (NOPOWER|BROKEN)) )
- pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]")
+ data["powermonitors"] = powermonitor_repository.powermonitor_data()
- data["powermonitors"] = pMonData
-
- if (powermonitor && !isnull(powermonitor.powernet))
+ if (powermonitor && !isnull(powermonitor.powernet))
+ if(select_monitor && (powermonitor.stat & (NOPOWER|BROKEN)))
+ powermonitor = null
+ return
data["poweravail"] = powermonitor.powernet.avail
- data["powerload"] = num2text(powermonitor.powernet.viewload,10)
- var/list/L = list()
- for(var/obj/machinery/power/terminal/term in powermonitor.powernet.nodes)
- if(istype(term.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = term.master
- L += A
-
- var/list/Status = list(0,0,1,1) // Status: off, auto-off, on, auto-on
- var/list/chg = list(0,1,1) // Charging: nope, charging, full
- for(var/obj/machinery/power/apc/A in L)
- apcData[++apcData.len] = list("Name" = html_encode(A.area.name), "Equipment" = Status[A.equipment+1], "Lights" = Status[A.lighting+1], "Environment" = Status[A.environ+1], "CellPct" = A.cell ? round(A.cell.percent(),1) : -1, "CellStatus" = A.cell ? chg[A.charging+1] : 0)
-
- data["apcs"] = apcData
-
+ data["powerload"] = num2text(powermonitor.powernet.viewload,10)
+ data["apcs"] = apc_repository.apc_data(powermonitor)
+
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 700, state = state)
diff --git a/paradise.dme b/paradise.dme
index 05bf2766401..e79ab1d4d08 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -187,6 +187,11 @@
#include "code\datums\spell.dm"
#include "code\datums\supplypacks.dm"
#include "code\datums\uplink_item.dm"
+#include "code\datums\cache\air_alarm.dm"
+#include "code\datums\cache\apc.dm"
+#include "code\datums\cache\cache.dm"
+#include "code\datums\cache\crew.dm"
+#include "code\datums\cache\powermonitor.dm"
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\events.dm"
#include "code\datums\helper_datums\global_iterator.dm"