mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-28 18:32:04 +00:00
* LINDA -> MILLA * Tiles now change their atmos mode properly. * Fixed a bug that made walls generate supercold air when deconstructed/destroyed. * Apply suggestions from code review Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Begone, var! * MILLA -> milla * Lint. * More lint. * Prevent negative/NaN atmos from spreading. * Made fires start more reliably. * Undef what the rest should not see. * Enums are nice. * Match LINDA better. * Debugging verbs. * Debug verb fixes. * Labelled more lavaland stuff with ATMOS_MODE_LAVALAND * Block superconductivity on a couple more things for Lavaland. * Updated milla.dll * Lavaland map fixes. * Missed a spot. * Begone, var! (again) * Add libmilla_ci.so for continuous integration tests. * Install/contributing instructions for MILLA. * Directional plasmaglass windows on shuttles shouldn't stop protecting from heat after moving. * Banish bad naming. * Better naming and debug stats for SSair. * Apply suggestions from code review Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Magic numbers and formatting. * Don't screw up the temperature during reactions. * Efficiency and readability. * Fix hotspots. * Removed redundant safety (MILLA will already output an error) * Optimizations. * oops * TGS build script update. * Change API of gas_mixture and how you get one from a turf. * Get in there. * so many vars * MILLA binary updates. * Lint * Made MT cost more honest. * Gave MILLA a read-only mode. * More read-only vs synchronized mode work. * Even more. * Synchronize disposals. * Updated a bunch of stuff to use SSair.synchronize or GM.synchronize. * MILLA <3 Tracy * lint * cargo fmt * more lint * Test needed MILLA sync. * Silence atmos machinery that's behaving as intended, but continue objecting to other potential failures to synchronize. * Push new MILLA DLL * Build MILLA * Update PR instructions for MILLA. * Add some fancy plasmaglass windows to the Lifebringers' ship. * The golems remembered that they should insulate *all* their engines. * First round of TM bugfixes. * Build MILLA * fix two lavaland ruin turf types * bunch more maps * fixes milla ci and makes the interesting turf verb better * Solid turfs can no longer conduct heat (for now...) * Made indoor tiles in beach and winter biodomes not lavaland air. * Re-added random IT teleport, adjusted warning message * Fixed a tinted window on Lavaland to be a plasglass window instead. * Made firelocks and holofans heatproof * Made RPD auto-wrench pipes if you have a wrench in your offhand. * Runtime fixes. * Made visuals update more reliably. * Lint * Update .github/CONTRIBUTING.md Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Build MILLA * The Syndicate have installed tiny fans on their research base. * The syndicate have figured out how to make plastitanium windows heatproof. * This is getting out of hand. Now there are two of them. * Un-break the auto-wrenching that I broke before committing. * Build MILLA * Build MILLA * Massive MILLA refactor, assorted bugfixes. * Build MILLA * Explicit typing. * Less sleeping/blocking. * Build MILLA * Yes, yes, this part can sleep. * Build MILLA * SSair reporting improvements. * Build MILLA * Please do not dock twice and splat yourself. * Build MILLA * Pls to not make SM go nuts. * Build MILLA * Build MILLA * Added stricter lower bounds on plasmafire, fixing perpetually-burning SM. * Build MILLA * Lint * Temporary logging, begone. * Build MILLA * Prevent hotspot strobing. * Add in radiate_to_spess behavior. * Build MILLA * progress * Compiling is good. * bugfixes * Progress. * Ruins update. * This one exists. * Fixup temporary hotspots to last longer than one tick. * Add/fix comments. * Cut the slash. * Fix test. * No sleep for you. * Build MILLA * Prevent nested MILLA safety from runtiming. * Build MILLA * Runtime fix. * Build MILLA * Fix canisters not updating icon when gas contents change. * Build MILLA * Build MILLA * Fixed an issue that made mechs very cold on environment air. * Build MILLA * oops * Build MILLA * Walls can make loud noises again. * Build MILLA * Fixes a rare runtime. * Build MILLA * Update .github/DOWNLOADING.md Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Review suggestions * Lint * Build MILLA * bound_mixtures now only contains mixtures that can be written * Build MILLA * Apply suggestions from code review Co-authored-by: Matt <116982774+Burzah@users.noreply.github.com> Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> * Build MILLA * Restore the original async behavior of pyro anomalies. * Build MILLA * Build MILLA * Make the safety assertion in /datum/milla_safe safer. * Build MILLA --------- Signed-off-by: Charlie Nolan <funnyman3595@gmail.com> Co-authored-by: FunnyMan3595 (Charlie Nolan) <funnyman@google.com> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Co-authored-by: paradisess13[bot] <165046124+paradisess13[bot]@users.noreply.github.com> Co-authored-by: warriorstar-orion <orion@snowfrost.garden> Co-authored-by: GDN <Roanrichards1@Gmail.com>
599 lines
21 KiB
Plaintext
599 lines
21 KiB
Plaintext
#define SSAIR_DEFERREDPIPENETS 1
|
|
#define SSAIR_PIPENETS 2
|
|
#define SSAIR_ATMOSMACHINERY 3
|
|
#define SSAIR_INTERESTING_TILES 4
|
|
#define SSAIR_HOTSPOTS 5
|
|
#define SSAIR_BOUND_MIXTURES 6
|
|
#define SSAIR_MILLA_TICK 7
|
|
|
|
SUBSYSTEM_DEF(air)
|
|
name = "Atmospherics"
|
|
init_order = INIT_ORDER_AIR
|
|
priority = FIRE_PRIORITY_AIR
|
|
wait = 5
|
|
flags = SS_BACKGROUND
|
|
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
|
offline_implications = "Turfs will no longer process atmos, and all atmospheric machines (including cryotubes) will no longer function. Shuttle call recommended."
|
|
cpu_display = SS_CPUDISPLAY_HIGH
|
|
|
|
/// How long we took for a full pass through the subsystem. Custom-tracked version of `cost`.
|
|
var/datum/resumable_cost_counter/cost_full = new()
|
|
/// How long we spent sleeping while waiting for MILLA to finish the last tick, shown in SS Info's C block as ZZZ.
|
|
var/datum/resumable_cost_counter/time_slept = new()
|
|
/// The cost of a pass through bound gas mixtures, shown in SS Info's C block as BM.
|
|
var/datum/resumable_cost_counter/cost_bound_mixtures = new()
|
|
/// The cost of a MILLA tick in ms, shown in SS Info's C block as MT.
|
|
var/cost_milla_tick = 0
|
|
/// The cost of a pass through interesting tiles, shown in SS Info's C block as IT.
|
|
var/datum/resumable_cost_counter/cost_interesting_tiles = new()
|
|
/// The cost of a pass through hotspots, shown in SS Info's C block as HS.
|
|
var/datum/resumable_cost_counter/cost_hotspots = new()
|
|
/// The cost of a pass through pipenets, shown in SS Info's C block as PN.
|
|
var/datum/resumable_cost_counter/cost_pipenets = new()
|
|
/// The cost of a pass through building pipenets, shown in SS Info's C block as DPN.
|
|
var/datum/resumable_cost_counter/cost_pipenets_to_build = new()
|
|
/// The cost of a pass through atmos machinery, shown in SS Info's C block as AM.
|
|
var/datum/resumable_cost_counter/cost_atmos_machinery = new()
|
|
|
|
/// The set of current bound mixtures. Shown in SS Info as BM:x+y, where x is the length at the start of the most recent processing, and y is the number of mixtures that have been added during processing.
|
|
var/list/bound_mixtures = list()
|
|
/// The original length of bound_mixtures.
|
|
var/original_bound_mixtures = 0
|
|
/// The number of bound mixtures we saw when we last stopped processing them.
|
|
var/last_bound_mixtures = 0
|
|
/// The number of bound mixtures that were added during this processing cycle.
|
|
var/added_bound_mixtures = 0
|
|
/// The length of the most recent interesting tiles list, shown in SS Info as IT.
|
|
var/interesting_tile_count = 0
|
|
/// The set of current active hotspots. Length shown in SS Info as HS.
|
|
var/list/hotspots = list()
|
|
/// The set of pipenets that need to be built. Length shown in SS Info as PTB.
|
|
var/list/pipenets_to_build = list()
|
|
/// The set of active pipenets. Length shown in SS Info as PN.
|
|
var/list/pipenets = list()
|
|
/// The set of active atmos machinery. Length shown in SS Info as AM.
|
|
var/list/atmos_machinery = list()
|
|
|
|
/// A list of atmos machinery to set up in Initialize.
|
|
var/list/machinery_to_construct = list()
|
|
|
|
/// Pipe overlay/underlay icon manager
|
|
var/datum/pipe_icon_manager/icon_manager
|
|
|
|
/// An arbitrary list of stuff currently being processed.
|
|
var/list/currentrun = list()
|
|
|
|
/// Which step we're currently on, used to let us resume if our time budget elapses.
|
|
var/currentpart = SSAIR_DEFERREDPIPENETS
|
|
|
|
/// Is MILLA currently in synchronous mode? TRUE if data is fresh and changes can be made, FALSE if data is from last tick and changes cannot be made (because this tick is still processing).
|
|
var/is_synchronous = TRUE
|
|
|
|
/// Are we currently running in a MILLA-safe context, i.e. is is_synchronous *guaranteed* to be TRUE. Nothing outside of this file should change this.
|
|
VAR_PRIVATE/in_milla_safe_code = FALSE
|
|
|
|
/// When did we start the last MILLA tick?
|
|
var/milla_tick_start = null
|
|
|
|
/// Is MILLA (and hence SSair) reliably healthy?
|
|
var/healthy = TRUE
|
|
|
|
/// When was MILLA last seen unhealthy?
|
|
var/last_unhealthy = 0
|
|
|
|
/// A list of callbacks waiting for MILLA to finish its tick and enter synchronous mode.
|
|
var/list/waiting_for_sync = list()
|
|
|
|
/// A cost counter for resumable, repeating processes.
|
|
/datum/resumable_cost_counter
|
|
var/last_complete_ms = 0
|
|
var/ongoing_ms = 0
|
|
|
|
/// Updates the counter based on the time spent making progress and whether we finished the task.
|
|
/datum/resumable_cost_counter/proc/record_progress(cost_ms, finished)
|
|
if(finished)
|
|
last_complete_ms = ongoing_ms + cost_ms
|
|
ongoing_ms = 0
|
|
else
|
|
ongoing_ms += cost_ms
|
|
|
|
/// Gets a display string for this cost counter.
|
|
/datum/resumable_cost_counter/proc/to_string()
|
|
if(ongoing_ms > last_complete_ms)
|
|
// We're in the middle of a task that's already longer than the prior one took in total, report the in-progress time instead, but mark that it's still incomplete with a +
|
|
return "[round(ongoing_ms, 1)]+"
|
|
return "[round(last_complete_ms, 1)]"
|
|
|
|
/datum/controller/subsystem/air/get_cost()
|
|
return cost_full.to_string()
|
|
|
|
/datum/controller/subsystem/air/get_stat_details()
|
|
var/list/msg = list()
|
|
msg += "C:{"
|
|
msg += "ZZZ:[time_slept.to_string()]|"
|
|
msg += "BM:[cost_bound_mixtures.to_string()]|"
|
|
msg += "MT:[round(cost_milla_tick,1)]|"
|
|
msg += "IT:[cost_interesting_tiles.to_string()]|"
|
|
msg += "HS:[cost_hotspots.to_string()]|"
|
|
msg += "PN:[cost_pipenets.to_string()]|"
|
|
msg += "PTB:[cost_pipenets_to_build.to_string()]|"
|
|
msg += "AM:[cost_atmos_machinery.to_string()]"
|
|
msg += "} "
|
|
msg += "BM:[original_bound_mixtures]+[added_bound_mixtures]|"
|
|
msg += "IT:[interesting_tile_count]|"
|
|
msg += "HS:[length(hotspots)]|"
|
|
msg += "PN:[length(pipenets)]|"
|
|
msg += "AM:[length(atmos_machinery)]|"
|
|
return msg.Join("")
|
|
|
|
/datum/controller/subsystem/air/get_metrics()
|
|
. = ..()
|
|
var/list/cust = list()
|
|
cust["hotspots"] = length(hotspots)
|
|
cust["interesting turfs"] = interesting_tile_count
|
|
.["cost"] = cost_full.last_complete_ms
|
|
.["custom"] = cust
|
|
|
|
/datum/controller/subsystem/air/Initialize()
|
|
in_milla_safe_code = TRUE
|
|
|
|
setup_overlays() // Assign icons and such for gas-turf-overlays
|
|
icon_manager = new() // Sets up icon manager for pipes
|
|
setup_allturfs()
|
|
setup_write_to_milla()
|
|
setup_atmos_machinery(GLOB.machines)
|
|
setup_pipenets(GLOB.machines)
|
|
for(var/obj/machinery/atmospherics/A in machinery_to_construct)
|
|
A.initialize_atmos_network()
|
|
|
|
in_milla_safe_code = FALSE
|
|
|
|
/datum/controller/subsystem/air/Recover()
|
|
hotspots = SSair.hotspots
|
|
pipenets_to_build = SSair.pipenets_to_build
|
|
pipenets = SSair.pipenets
|
|
atmos_machinery = SSair.atmos_machinery
|
|
machinery_to_construct = SSair.machinery_to_construct
|
|
icon_manager = SSair.icon_manager
|
|
currentrun = SSair.currentrun
|
|
currentpart = SSair.currentpart
|
|
is_synchronous = SSair.is_synchronous
|
|
|
|
/datum/controller/subsystem/air/fire(resumed = 0)
|
|
// All atmos stuff assumes MILLA is synchronous. Ensure it actually is.
|
|
if(!is_synchronous)
|
|
var/timer = TICK_USAGE_REAL
|
|
|
|
while(!is_synchronous)
|
|
// Sleep for 1ms.
|
|
sleep(0.01)
|
|
if(MC_TICK_CHECK)
|
|
time_slept.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
return
|
|
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
time_slept.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), TRUE)
|
|
|
|
fire_sleepless(resumed)
|
|
|
|
/datum/controller/subsystem/air/proc/fire_sleepless(resumed)
|
|
// Any proc that wants MILLA to be synchronous should not sleep.
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
in_milla_safe_code = TRUE
|
|
|
|
var/timer = TICK_USAGE_REAL
|
|
|
|
if(currentpart == SSAIR_DEFERREDPIPENETS || !resumed)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
build_pipenets(resumed)
|
|
|
|
cost_pipenets_to_build.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_PIPENETS
|
|
|
|
if(currentpart == SSAIR_PIPENETS || !resumed)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
process_pipenets(resumed)
|
|
|
|
cost_pipenets.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_ATMOSMACHINERY
|
|
|
|
if(currentpart == SSAIR_ATMOSMACHINERY)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
process_atmos_machinery(resumed)
|
|
|
|
cost_atmos_machinery.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_INTERESTING_TILES
|
|
|
|
if(currentpart == SSAIR_INTERESTING_TILES)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
process_interesting_tiles(resumed)
|
|
|
|
cost_interesting_tiles.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_HOTSPOTS
|
|
|
|
if(currentpart == SSAIR_HOTSPOTS)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
process_hotspots(resumed)
|
|
|
|
cost_hotspots.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_BOUND_MIXTURES
|
|
|
|
if(currentpart == SSAIR_BOUND_MIXTURES)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
process_bound_mixtures(resumed)
|
|
|
|
cost_bound_mixtures.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_MILLA_TICK
|
|
|
|
if(currentpart == SSAIR_MILLA_TICK)
|
|
timer = TICK_USAGE_REAL
|
|
|
|
spawn_milla_tick_thread()
|
|
is_synchronous = FALSE
|
|
|
|
cost_milla_tick = MC_AVERAGE(cost_milla_tick, get_milla_tick_time())
|
|
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
|
if(state == SS_PAUSED || state == SS_PAUSING)
|
|
in_milla_safe_code = FALSE
|
|
return
|
|
resumed = 0
|
|
|
|
currentpart = SSAIR_DEFERREDPIPENETS
|
|
in_milla_safe_code = FALSE
|
|
|
|
/datum/controller/subsystem/air/proc/build_pipenets(resumed = 0)
|
|
if(!resumed)
|
|
src.currentrun = pipenets_to_build.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
var/obj/machinery/atmospherics/A = currentrun[length(currentrun)]
|
|
currentrun.len--
|
|
if(A)
|
|
A.build_network(remove_deferral = TRUE)
|
|
else
|
|
pipenets_to_build.Remove(A)
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_pipenets(resumed = 0)
|
|
if(!resumed)
|
|
src.currentrun = pipenets.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
var/datum/pipeline/thing = currentrun[length(currentrun)]
|
|
currentrun.len--
|
|
if(thing)
|
|
thing.process()
|
|
else
|
|
pipenets.Remove(thing)
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
|
|
var/seconds = wait * 0.1
|
|
if(!resumed)
|
|
src.currentrun = atmos_machinery.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
var/obj/machinery/atmospherics/M = currentrun[length(currentrun)]
|
|
currentrun.len--
|
|
if(isnull(M) || (M.process_atmos(seconds) == PROCESS_KILL))
|
|
atmos_machinery -= M
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_hotspots(resumed = 0)
|
|
if(!resumed)
|
|
src.currentrun = hotspots.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
var/obj/effect/hotspot/H = currentrun[length(currentrun)]
|
|
currentrun.len--
|
|
if(H)
|
|
H.process()
|
|
else
|
|
hotspots -= H
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_interesting_tiles(resumed = 0)
|
|
if(!resumed)
|
|
// Fetch the list of interesting tiles from MILLA.
|
|
src.currentrun = get_interesting_atmos_tiles()
|
|
interesting_tile_count = length(src.currentrun) / MILLA_INTERESTING_TILE_SIZE
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
// Pop a tile off the list.
|
|
var/offset = length(currentrun) - MILLA_INTERESTING_TILE_SIZE
|
|
var/turf/T = currentrun[offset + MILLA_INDEX_TURF]
|
|
if(!istype(T))
|
|
currentrun.len -= MILLA_INTERESTING_TILE_SIZE
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
continue
|
|
|
|
var/reasons = currentrun[offset + MILLA_INDEX_INTERESTING_REASONS]
|
|
var/x_flow = currentrun[offset + MILLA_INDEX_AIRFLOW_X]
|
|
var/y_flow = currentrun[offset + MILLA_INDEX_AIRFLOW_Y]
|
|
var/milla_tile = currentrun.Copy(offset + 1, offset + 1 + MILLA_TILE_SIZE + 1)
|
|
currentrun.len -= MILLA_INTERESTING_TILE_SIZE
|
|
|
|
// Bind the MILLA tile we got, if needed.
|
|
if(isnull(T.bound_air))
|
|
bind_turf(T, milla_tile)
|
|
else if(T.bound_air.lastread < times_fired)
|
|
T.bound_air.copy_from_milla(milla_tile)
|
|
T.bound_air.lastread = times_fired
|
|
T.bound_air.readonly = null
|
|
T.bound_air.dirty = FALSE
|
|
T.bound_air.synchronized = FALSE
|
|
|
|
if(reasons & MILLA_INTERESTING_REASON_DISPLAY)
|
|
var/turf/simulated/S = T
|
|
if(istype(S))
|
|
S.update_visuals()
|
|
|
|
if(reasons & MILLA_INTERESTING_REASON_HOT)
|
|
var/datum/gas_mixture/air = T.get_readonly_air()
|
|
T.hotspot_expose(air.temperature(), CELL_VOLUME)
|
|
for(var/atom/movable/item in T)
|
|
item.temperature_expose(air, air.temperature(), CELL_VOLUME)
|
|
T.temperature_expose(air, air.temperature(), CELL_VOLUME)
|
|
|
|
if(reasons & MILLA_INTERESTING_REASON_WIND)
|
|
T.high_pressure_movements(x_flow, y_flow)
|
|
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_bound_mixtures(resumed = 0)
|
|
if(!resumed)
|
|
original_bound_mixtures = length(bound_mixtures)
|
|
last_bound_mixtures = length(bound_mixtures)
|
|
// Note that we do NOT copy this list to src.currentrun. We're fine with things being added to it as we work, because it all needs to get written before the next MILLA tick.
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = bound_mixtures
|
|
added_bound_mixtures = length(currentrun) - last_bound_mixtures
|
|
while(length(currentrun))
|
|
var/datum/gas_mixture/bound_to_turf/mixture = currentrun[length(currentrun)]
|
|
currentrun.len--
|
|
mixture.synchronized = FALSE
|
|
if(mixture.dirty)
|
|
// This is one of two places expected to call this otherwise-unsafe method.
|
|
mixture.private_unsafe_write()
|
|
mixture.dirty = FALSE
|
|
if(MC_TICK_CHECK)
|
|
last_bound_mixtures = length(bound_mixtures)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/setup_allturfs(list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz)))
|
|
for(var/turf/T as anything in turfs_to_init)
|
|
T.Initialize_Atmos(times_fired)
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/air/proc/setup_allturfs_sleepless(list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz)))
|
|
for(var/turf/T as anything in turfs_to_init)
|
|
T.Initialize_Atmos(times_fired)
|
|
|
|
/datum/controller/subsystem/air/proc/setup_write_to_milla()
|
|
var/watch = start_watch()
|
|
log_startup_progress("Writing tiles to MILLA...")
|
|
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/cache = bound_mixtures
|
|
var/count = length(cache)
|
|
while(length(cache))
|
|
var/datum/gas_mixture/bound_to_turf/mixture = cache[length(cache)]
|
|
cache.len--
|
|
if(mixture.dirty)
|
|
in_milla_safe_code = TRUE
|
|
// This is one of two places expected to call this otherwise-unsafe method.
|
|
mixture.private_unsafe_write()
|
|
in_milla_safe_code = FALSE
|
|
mixture.bound_turf.bound_air = null
|
|
mixture.bound_turf = null
|
|
CHECK_TICK
|
|
|
|
log_startup_progress("Wrote [count] tiles in [stop_watch(watch)]s.")
|
|
|
|
/datum/controller/subsystem/air/proc/setup_atmos_machinery(list/machines_to_init)
|
|
var/watch = start_watch()
|
|
log_startup_progress("Initializing atmospherics machinery...")
|
|
var/count = _setup_atmos_machinery(machines_to_init)
|
|
log_startup_progress("Initialized [count] atmospherics machines in [stop_watch(watch)]s.")
|
|
|
|
// this underscored variant is so that we can have a means of late initing
|
|
// atmos machinery without a loud announcement to the world
|
|
/datum/controller/subsystem/air/proc/_setup_atmos_machinery(list/machines_to_init)
|
|
var/count = 0
|
|
for(var/obj/machinery/atmospherics/A in machines_to_init)
|
|
A.atmos_init()
|
|
count++
|
|
CHECK_TICK
|
|
return count
|
|
|
|
//this can't be done with setup_atmos_machinery() because
|
|
// all atmos machinery has to initalize before the first
|
|
// pipenet can be built.
|
|
/datum/controller/subsystem/air/proc/setup_pipenets(list/pipes)
|
|
var/watch = start_watch()
|
|
log_startup_progress("Initializing pipe pipenets...")
|
|
var/count = _setup_pipenets(pipes)
|
|
log_startup_progress("Initialized [count] pipenets in [stop_watch(watch)]s.")
|
|
|
|
// An underscored wrapper that exists for the same reason
|
|
// the machine init wrapper does
|
|
/datum/controller/subsystem/air/proc/_setup_pipenets(list/pipes)
|
|
var/count = 0
|
|
for(var/obj/machinery/atmospherics/machine in pipes)
|
|
machine.build_network()
|
|
count++
|
|
return count
|
|
|
|
/obj/effect/overlay/turf
|
|
icon = 'icons/effects/tile_effects.dmi'
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
anchored = TRUE // should only appear in vis_contents, but to be safe
|
|
layer = FLY_LAYER
|
|
appearance_flags = TILE_BOUND | RESET_TRANSFORM | RESET_COLOR
|
|
|
|
/obj/effect/overlay/turf/plasma
|
|
icon_state = "plasma"
|
|
|
|
/obj/effect/overlay/turf/sleeping_agent
|
|
icon_state = "sleeping_agent"
|
|
|
|
/datum/controller/subsystem/air/proc/setup_overlays()
|
|
GLOB.plmaster = new /obj/effect/overlay/turf/plasma
|
|
GLOB.slmaster = new /obj/effect/overlay/turf/sleeping_agent
|
|
|
|
/datum/controller/subsystem/air/proc/bind_turf(turf/T, list/milla_tile = null)
|
|
var/datum/gas_mixture/bound_to_turf/B = new()
|
|
T.bound_air = B
|
|
B.bound_turf = T
|
|
if(isnull(milla_tile))
|
|
milla_tile = new/list(MILLA_TILE_SIZE)
|
|
get_tile_atmos(T, milla_tile)
|
|
B.copy_from_milla(milla_tile)
|
|
B.lastread = src.times_fired
|
|
B.readonly = null
|
|
B.dirty = FALSE
|
|
B.synchronized = FALSE
|
|
|
|
|
|
/// Similar to addtimer, but triggers once MILLA enters synchronous mode.
|
|
/datum/controller/subsystem/air/proc/synchronize(datum/milla_safe/CB)
|
|
// Any proc that wants MILLA to be synchronous should not sleep.
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
if(is_synchronous)
|
|
var/was_safe = SSair.in_milla_safe_code
|
|
SSair.in_milla_safe_code = TRUE
|
|
// This is one of two intended places to call this otherwise-unsafe proc.
|
|
CB.private_unsafe_invoke()
|
|
SSair.in_milla_safe_code = was_safe
|
|
return
|
|
|
|
waiting_for_sync += CB
|
|
|
|
/datum/controller/subsystem/air/proc/is_in_milla_safe_code()
|
|
return in_milla_safe_code
|
|
|
|
/datum/controller/subsystem/air/proc/on_milla_tick_finished()
|
|
is_synchronous = TRUE
|
|
in_milla_safe_code = TRUE
|
|
for(var/datum/milla_safe/CB as anything in waiting_for_sync)
|
|
// This is one of two intended places to call this otherwise-unsafe proc.
|
|
CB.private_unsafe_invoke()
|
|
waiting_for_sync.Cut()
|
|
in_milla_safe_code = FALSE
|
|
|
|
/proc/milla_tick_finished()
|
|
// Any proc that wants MILLA to be synchronous should not sleep.
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
SSair.on_milla_tick_finished()
|
|
|
|
/// Create a subclass of this and implement `on_run` to manipulate tile air safely.
|
|
/datum/milla_safe
|
|
var/run_args = list()
|
|
|
|
/// All subclasses should implement this.
|
|
/datum/milla_safe/proc/on_run(...)
|
|
// Any proc that wants MILLA to be synchronous should not sleep.
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
CRASH("[src.type] does not implement on_run")
|
|
|
|
/// Call this to make the subclass run when it's safe to do so. Args will be passed to on_run.
|
|
/datum/milla_safe/proc/invoke_async(...)
|
|
run_args = args.Copy()
|
|
SSair.synchronize(src)
|
|
|
|
/// Do not call this yourself. This is what is called to run your code from a safe context.
|
|
/datum/milla_safe/proc/private_unsafe_invoke()
|
|
soft_assert_safe()
|
|
on_run(arglist(run_args))
|
|
|
|
/// Used internally to check that we're running safely, but without breaking things worse if we aren't.
|
|
/datum/milla_safe/proc/soft_assert_safe()
|
|
ASSERT(SSair.is_in_milla_safe_code())
|
|
|
|
/// Fetch the air for a turf. Only use from `on_run`.
|
|
/datum/milla_safe/proc/get_turf_air(turf/T)
|
|
RETURN_TYPE(/datum/gas_mixture)
|
|
soft_assert_safe()
|
|
// This is one of two intended places to call this otherwise-unsafe proc.
|
|
var/datum/gas_mixture/bound_to_turf/air = T.private_unsafe_get_air()
|
|
if(air.lastread < SSair.times_fired)
|
|
var/list/milla_tile = new/list(MILLA_TILE_SIZE)
|
|
get_tile_atmos(T, milla_tile)
|
|
air.copy_from_milla(milla_tile)
|
|
air.lastread = SSair.times_fired
|
|
air.readonly = null
|
|
air.dirty = FALSE
|
|
if(!air.synchronized)
|
|
air.synchronized = TRUE
|
|
SSair.bound_mixtures += air
|
|
return air
|
|
|
|
/// Add air to a turf. Only use from `on_run`.
|
|
/datum/milla_safe/proc/add_turf_air(turf/T, datum/gas_mixture/air)
|
|
var/datum/gas_mixture/turf_air = get_turf_air(T)
|
|
turf_air.merge(air)
|
|
|
|
/// Completely replace the air for a turf. Only use from `on_run`.
|
|
/datum/milla_safe/proc/set_turf_air(turf/T, datum/gas_mixture/air)
|
|
var/datum/gas_mixture/turf_air = get_turf_air(T)
|
|
turf_air.copy_from(air)
|
|
|
|
#undef SSAIR_DEFERREDPIPENETS
|
|
#undef SSAIR_PIPENETS
|
|
#undef SSAIR_ATMOSMACHINERY
|
|
#undef SSAIR_INTERESTING_TILES
|
|
#undef SSAIR_HOTSPOTS
|
|
#undef SSAIR_BOUND_MIXTURES
|
|
#undef SSAIR_MILLA_TICK
|