From 073f462e1be1f932e736809a52f024c30eef9762 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Sun, 25 Aug 2013 22:42:56 -0700 Subject: [PATCH 1/9] WIP ZAS rework. --- code/ZAS/FEA_gas_mixture.dm | 2 +- code/ZAS/FEA_system.dm | 82 +++++++++++++------ code/ZAS/ZAS_Turfs.dm | 77 +++-------------- code/ZAS/ZAS_Zones.dm | 5 +- code/controllers/master_controller.dm | 4 +- code/game/machinery/doors/door.dm | 34 ++------ code/game/machinery/doors/windowdoor.dm | 9 +- code/game/machinery/shieldgen.dm | 15 +--- code/game/objects/effects/effect_system.dm | 15 +--- code/game/objects/structures/mineral_doors.dm | 17 +--- .../objects/structures/windoor_assembly.dm | 9 +- code/game/objects/structures/window.dm | 18 +--- 12 files changed, 97 insertions(+), 190 deletions(-) diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm index 8b7ab992c9..5e2e64cb6e 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/FEA_gas_mixture.dm @@ -8,7 +8,7 @@ What are the archived variables for? #define SPECIFIC_HEAT_AIR 20 #define SPECIFIC_HEAT_CDO 30 #define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \ - (carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN) + max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN) #define MINIMUM_HEAT_CAPACITY 0.0003 #define QUANTIZE(variable) (round(variable,0.0001)) diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm index c2a33ad99d..0f246fa6ee 100644 --- a/code/ZAS/FEA_system.dm +++ b/code/ZAS/FEA_system.dm @@ -87,17 +87,24 @@ atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) var/datum/controller/air_system/air_master -/datum/controller/air_system/ - //Geoemetry lists +/datum/controller/air_system + //Geometry lists var/list/turfs_with_connections = list() var/list/active_hotspots = list() //Special functions lists + var/reconsidering_zones = FALSE var/list/tiles_to_reconsider_zones = list() + var/list/tiles_to_reconsider_alternate //Geometry updates lists + var/updating_tiles = FALSE var/list/tiles_to_update = list() + var/list/tiles_to_update_alternate + + var/checking_connections = FALSE var/list/connections_to_check = list() + var/list/connections_to_check_alternate var/current_cycle = 0 var/update_delay = 5 //How long between check should it try to process atmos again. @@ -106,20 +113,7 @@ var/datum/controller/air_system/air_master var/tick_progress = 0 -/* process() - //Call this to process air movements for a cycle - - process_rebuild_select_groups() - //Used by process() - //Warning: Do not call this - - rebuild_group(datum/air_group) - //Used by process_rebuild_select_groups() - //Warning: Do not call this, add the group to air_master.groups_to_rebuild instead - */ - - -/datum/controller/air_system/proc/setup() +/datum/controller/air_system/proc/Tetup() //Purpose: Call this at the start to setup air groups geometry // (Warning: Very processor intensive but only must be done once per round) //Called by: Gameticker/Master controller @@ -147,10 +141,11 @@ var/datum/controller/air_system/air_master Total Simulated Turfs: [simulated_turf_count] Total Zones: [zones.len] Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]"} - /* - spawn start() -/datum/controller/air_system/proc/start() +// spawn Start() + + +/datum/controller/air_system/proc/Start() //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. //Called by: Master controller //Inputs: None. @@ -162,26 +157,38 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun while(1) if(!kill_air) current_cycle++ - var/success = tick() //Changed so that a runtime does not crash the ticker. + var/success = Tick() //Changed so that a runtime does not crash the ticker. if(!success) //Runtimed. failed_ticks++ if(failed_ticks > 20) world << "ERROR IN ATMOS TICKER. Killing air simulation!" kill_air = 1 sleep(max(5,update_delay*tick_multiplier)) - */ -/datum/controller/air_system/proc/tick() + +/datum/controller/air_system/proc/Tick() . = 1 //Set the default return value, for runtime detection. + //If there are tiles to update, do so. tick_progress = "update_air_properties" - if(tiles_to_update.len) //If there are tiles to update, do so. + if(tiles_to_update.len) + updating_tiles = TRUE + for(var/turf/simulated/T in tiles_to_update) if(. && T && !T.update_air_properties()) - . = 0 //If a runtime occured, make sure we can sense it. - //message_admins("ZASALERT: Unable run turf/simualted/update_air_properties()") + //If a runtime occured, make sure we can sense it. + . = 0 + + updating_tiles = FALSE + if(.) - tiles_to_update = list() + if(tiles_to_update_alternate) + tiles_to_update = tiles_to_update_alternate + else + tiles_to_update = list() + + else if(tiles_to_update_alternate) + tiles_to_update |= tiles_to_update_alternate //Check sanity on connection objects. if(.) @@ -218,4 +225,25 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun . = 0 if(.) - tick_progress = "success" \ No newline at end of file + tick_progress = "success" + + +/datum/controller/air_system/proc/AddTurfToUpdate(turf/simulated/outdated_turf) + var/list/tiles_to_check = list() + + if(istype(outdated_turf)) + tiles_to_check |= outdated_turf + + if(istype(outdated_turf, /turf)) + for(var/direction in cardinal) + var/turf/simulated/adjacent_turf = get_step(outdated_turf, direction) + if(istype(adjacent_turf)) + tiles_to_check |= adjacent_turf + + if(updating_tiles) + if(!tiles_to_update_alternate) + tiles_to_update_alternate = tiles_to_check + else + tiles_to_update_alternate |= tiles_to_check + else + tiles_to_update |= tiles_to_check \ No newline at end of file diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 04af9a0528..9851eb2fa5 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -135,8 +135,8 @@ if(!zone && !blocks_air) //No zone, but not a wall. for(var/direction in DoorDirections) //Check door directions first. - if(air_check_directions&direction) - var/turf/simulated/T = get_step(src,direction) + if(air_check_directions & direction) + var/turf/simulated/T = get_step(src, direction) if(!istype(T)) continue if(T.zone) @@ -144,7 +144,7 @@ break if(!zone) //Still no zone for(var/direction in CounterDoorDirections) //Check the others second. - if(air_check_directions&direction) + if(air_check_directions & direction) var/turf/simulated/T = get_step(src,direction) if(!istype(T)) continue @@ -161,73 +161,20 @@ for(var/connection/C in air_master.turfs_with_connections["\ref[src]"]) air_master.connections_to_check |= C - if(zone && !zone.rebuild) + if(zone && !zone.rebuild && CanPass(null, src, 0, 0)) + for(var/direction in cardinal) var/turf/T = get_step(src,direction) if(!istype(T)) continue //I can connect to air in this direction - if(air_check_directions&direction) + if(air_check_directions & direction && !(air_directions_archived & direction)) - //If either block air, we must look to see if the adjacent turfs need rebuilt. - if(!CanPass(null, T, 0, 0)) - - //Target blocks air - if(!T.CanPass(null, T, 0, 0)) - var/turf/NT = get_step(T, direction) - - //If that turf is in my zone still, rebuild. - if(istype(NT,/turf/simulated) && NT in zone.contents) - zone.rebuild = 1 - - //If that is an unsimulated tile in my zone, see if we need to rebuild or just remove. - else if(istype(NT) && NT in zone.unsimulated_tiles) - var/consider_rebuild = 0 - for(var/d in cardinal) - var/turf/UT = get_step(NT,d) - if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild - consider_rebuild = 1 - break - if(consider_rebuild) - zone.rebuild = 1 //Gotta check if we need to rebuild, dammit - else - zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~ - - //To make a closed connection through closed door. - ZConnect(T, src) - - //If I block air. - else if(T.zone && !T.zone.rebuild) - var/turf/NT = get_step(src, reverse_direction(direction)) - - //If I am splitting a zone, rebuild. - if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents))) - T.zone.rebuild = 1 - - //If NT is unsimulated, parse if I should remove it or rebuild. - else if(istype(NT) && NT in T.zone.unsimulated_tiles) - var/consider_rebuild = 0 - for(var/d in cardinal) - var/turf/UT = get_step(NT,d) - if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild - consider_rebuild = 1 - break - - //Needs rebuilt. - if(consider_rebuild) - T.zone.rebuild = 1 - - //Not adjacent to anything, and unsimulated. Goodbye~ - else - T.zone.RemoveTurf(NT) - - else - //Produce connection through open door. - ZConnect(src,T) + ZConnect(src,T) //Something like a wall was built, changing the geometry. - else if(air_directions_archived&direction) + else if(!(air_check_directions & direction) && air_directions_archived & direction) var/turf/NT = get_step(T, direction) //If the tile is in our own zone, and we cannot connect to it, better rebuild. @@ -289,13 +236,13 @@ return 0 for(var/obj/obstacle in src) - if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction) + if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) continue if(!obstacle.CanPass(null, T, 1.5, 1)) return 0 for(var/obj/obstacle in T) - if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction) + if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) continue if(!obstacle.CanPass(null, src, 1.5, 1)) return 0 @@ -311,13 +258,13 @@ return 0 for(var/obj/obstacle in src) - if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction) + if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) continue if(!obstacle.CanPass(null, T, 0, 0)) return 0 for(var/obj/obstacle in T) - if(istype(obstacle, /obj/machinery/door) && !obstacle:air_properties_vary_with_direction) + if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) continue if(!obstacle.CanPass(null, src, 0, 0)) return 0 diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index 860f57cd37..a3667a0180 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -383,7 +383,7 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) unsim_co2 *= correction_ratio unsim_nitrogen *= correction_ratio unsim_plasma *= correction_ratio - unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen,unsim_co2,unsim_nitrogen,unsim_plasma) + unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma) var ratio = sharing_lookup_table[6] @@ -402,6 +402,9 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) co2_avg = (full_co2 + unsim_co2) / (size + share_size) plasma_avg = (full_plasma + unsim_plasma) / (size + share_size) + temp_avg = 0 + + if((full_heat_capacity + unsim_heat_capacity) > 0) temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity) if(sharing_lookup_table.len >= unsimulated_tiles.len) //6 or more interconnecting tiles will max at 42% of air moved per tick. diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index be684e3201..1a543381da 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -56,7 +56,7 @@ datum/controller/game_controller/proc/setup() if(!air_master) air_master = new /datum/controller/air_system() - air_master.setup() + air_master.Setup() if(!ticker) ticker = new /datum/controller/gameticker() @@ -127,7 +127,7 @@ datum/controller/game_controller/proc/process() last_thing_processed = air_master.type air_master.current_cycle++ - if(!air_master.tick()) //Runtimed. + if(!air_master.Tick()) //Runtimed. air_master.failed_ticks++ if(air_master.failed_ticks > 5) world << "RUNTIMES IN ATMOS TICKER. Killing air simulation!" diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 6aec44f7f1..0f64866f45 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -257,36 +257,12 @@ return 1 /obj/machinery/door/proc/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 + if(!air_master) + return 0 - var/turf/simulated/source = loc - var/turf/simulated/north = get_step(source,NORTH) - var/turf/simulated/south = get_step(source,SOUTH) - var/turf/simulated/east = get_step(source,EAST) - var/turf/simulated/west = get_step(source,WEST) - - update_heat_protection(loc) - - if(istype(source)) air_master.tiles_to_update += source - if(istype(north)) air_master.tiles_to_update += north - if(istype(south)) air_master.tiles_to_update += south - if(istype(east)) air_master.tiles_to_update += east - if(istype(west)) air_master.tiles_to_update += west - - if(width > 1) - var/turf/simulated/next_turf = src - var/step_dir = turn(dir, 180) - for(var/current_step = 2, current_step <= width, current_step++) - next_turf = get_step(src, step_dir) - north = get_step(next_turf, step_dir) - east = get_step(next_turf, turn(step_dir, 90)) - south = get_step(next_turf, turn(step_dir, -90)) - - update_heat_protection(next_turf) - - if(istype(north)) air_master.tiles_to_update |= north - if(istype(south)) air_master.tiles_to_update |= south - if(istype(east)) air_master.tiles_to_update |= east + for(var/turf/simulated/turf in locs) + update_heat_protection(turf) + air_master.AddTurfToUpdate(turf) return 1 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 66184774c4..c8d0d4d110 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -15,13 +15,10 @@ /obj/machinery/door/window/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 + if(!air_master) + return 0 - var/turf/simulated/source = get_turf(src) - var/turf/simulated/target = get_step(source,dir) - - if(istype(source)) air_master.tiles_to_update |= source - if(istype(target)) air_master.tiles_to_update |= target + air_master.AddTurfToUpdate(get_turf(src)) return 1 diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 6b657bda78..640fc00afc 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -27,19 +27,10 @@ //Looks like copy/pasted code... I doubt 'need_rebuild' is even used here - Nodrak /obj/machinery/shield/proc/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 + if(!air_master) + return 0 - var/turf/simulated/source = get_turf(src) - var/turf/simulated/north = get_step(source,NORTH) - var/turf/simulated/south = get_step(source,SOUTH) - var/turf/simulated/east = get_step(source,EAST) - var/turf/simulated/west = get_step(source,WEST) - - if(istype(source)) air_master.tiles_to_update |= source - if(istype(north)) air_master.tiles_to_update |= north - if(istype(south)) air_master.tiles_to_update |= south - if(istype(east)) air_master.tiles_to_update |= east - if(istype(west)) air_master.tiles_to_update |= west + air_master.AddTurfToUpdate(get_turf(src)) return 1 diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index d3e7144297..c0f783c52d 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -1030,19 +1030,10 @@ steam.start() -- spawns the effect proc/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 + if(!air_master) + return 0 - var/turf/simulated/source = get_turf(src) - var/turf/simulated/north = get_step(source,NORTH) - var/turf/simulated/south = get_step(source,SOUTH) - var/turf/simulated/east = get_step(source,EAST) - var/turf/simulated/west = get_step(source,WEST) - - if(istype(source)) air_master.tiles_to_update |= source - if(istype(north)) air_master.tiles_to_update |= north - if(istype(south)) air_master.tiles_to_update |= south - if(istype(east)) air_master.tiles_to_update |= east - if(istype(west)) air_master.tiles_to_update |= west + air_master.AddTurfToUpdate(get_turf(src)) return 1 diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 04b3bdc19c..64e9623fca 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -156,20 +156,9 @@ return proc/update_nearby_tiles(need_rebuild) //Copypasta from airlock code - if(!air_master) return 0 - - var/turf/simulated/source = loc - var/turf/simulated/north = get_step(source,NORTH) - var/turf/simulated/south = get_step(source,SOUTH) - var/turf/simulated/east = get_step(source,EAST) - var/turf/simulated/west = get_step(source,WEST) - - if(istype(source)) air_master.tiles_to_update += source - if(istype(north)) air_master.tiles_to_update += north - if(istype(south)) air_master.tiles_to_update += south - if(istype(east)) air_master.tiles_to_update += east - if(istype(west)) air_master.tiles_to_update += west - + if(!air_master) + return 0 + air_master.AddTurfToUpdate(get_turf(src)) return 1 /obj/structure/mineral_door/iron diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 478f6989ba..f13f3f1dec 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -294,12 +294,9 @@ obj/structure/windoor_assembly/Del() return /obj/structure/windoor_assembly/proc/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 + if(!air_master) + return 0 - var/turf/simulated/source = loc - var/turf/simulated/target = get_step(source,dir) - - if(istype(source)) air_master.tiles_to_update += source - if(istype(target)) air_master.tiles_to_update += target + air_master.AddTurfToUpdate(loc) return 1 diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index bb38bbcd85..22d9c1a0b6 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -316,21 +316,9 @@ //This proc has to do with airgroups and atmos, it has nothing to do with smoothwindows, that's update_nearby_tiles(). /obj/structure/window/proc/update_nearby_tiles(need_rebuild) - if(!air_master) return 0 - if(!dir in cardinal) - var/turf/simulated/source = get_turf(src) - if(istype(source)) - air_master.tiles_to_update |= source - for(var/dir in cardinal) - var/turf/simulated/target = get_step(source,dir) - if(istype(target)) air_master.tiles_to_update |= target - return 1 - - var/turf/simulated/source = get_turf(src) - var/turf/simulated/target = get_step(source,dir) - - if(istype(source)) air_master.tiles_to_update |= source - if(istype(target)) air_master.tiles_to_update |= target + if(!air_master) + return 0 + AddTurfToUpdate( return 1 From e8f9d19c7545359adaa8654e83ae90183e8bc410 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Mon, 26 Aug 2013 20:57:38 -0700 Subject: [PATCH 2/9] Completed ZAS rework. Needs testing, and consideration to make zones sleep. --- code/ZAS/Debug.dm | 11 +++++ code/ZAS/FEA_system.dm | 66 ++++++++++++++++++++++---- code/ZAS/ZAS_Turfs.dm | 5 +- code/ZAS/ZAS_Zones.dm | 10 ++-- code/controllers/master_controller.dm | 4 +- code/game/objects/structures/window.dm | 2 +- code/game/turfs/turf.dm | 7 ++- code/modules/admin/admin_verbs.dm | 6 +-- code/modules/admin/verbs/mapping.dm | 1 + 9 files changed, 85 insertions(+), 27 deletions(-) diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index 6586cbaaec..69047b56b6 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -1,3 +1,14 @@ +client/proc/ZoneTick() + set category = "Debug" + set name = "Process Atmos" + + var/result = air_master.Tick() + if(result) + src << "Sucessfully Processed." + + else + src << "Failed to process! ([air_master.tick_progress])" + client/proc/Zone_Info(turf/T as null|turf) set category = "Debug" diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm index 0f246fa6ee..0f5351ce1b 100644 --- a/code/ZAS/FEA_system.dm +++ b/code/ZAS/FEA_system.dm @@ -53,7 +53,6 @@ Important Procedures */ -var/kill_air = 0 var/tick_multiplier = 2 atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) @@ -113,7 +112,7 @@ var/datum/controller/air_system/air_master var/tick_progress = 0 -/datum/controller/air_system/proc/Tetup() +/datum/controller/air_system/proc/Setup() //Purpose: Call this at the start to setup air groups geometry // (Warning: Very processor intensive but only must be done once per round) //Called by: Gameticker/Master controller @@ -155,20 +154,21 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun set background = 1 while(1) - if(!kill_air) - current_cycle++ + if(!air_processing_killed) var/success = Tick() //Changed so that a runtime does not crash the ticker. if(!success) //Runtimed. failed_ticks++ if(failed_ticks > 20) world << "ERROR IN ATMOS TICKER. Killing air simulation!" - kill_air = 1 + air_processing_killed = 1 sleep(max(5,update_delay*tick_multiplier)) /datum/controller/air_system/proc/Tick() . = 1 //Set the default return value, for runtime detection. + current_cycle++ + //If there are tiles to update, do so. tick_progress = "update_air_properties" if(tiles_to_update.len) @@ -184,28 +184,48 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun if(.) if(tiles_to_update_alternate) tiles_to_update = tiles_to_update_alternate + tiles_to_update_alternate = null else tiles_to_update = list() else if(tiles_to_update_alternate) tiles_to_update |= tiles_to_update_alternate + tiles_to_update_alternate = null //Check sanity on connection objects. if(.) tick_progress = "connections_to_check" if(connections_to_check.len) + checking_connections = TRUE + for(var/connection/C in connections_to_check) C.CheckPassSanity() - connections_to_check = list() + + checking_connections = FALSE + + if(connections_to_check_alternate) + connections_to_check = connections_to_check_alternate + connections_to_check_alternate = null + else + connections_to_check = list() //Ensure tiles still have zones. if(.) tick_progress = "tiles_to_reconsider_zones" if(tiles_to_reconsider_zones.len) + reconsidering_zones = TRUE + for(var/turf/simulated/T in tiles_to_reconsider_zones) if(!T.zone) new /zone(T) - tiles_to_reconsider_zones = list() + + reconsidering_zones = FALSE + + if(tiles_to_reconsider_alternate) + tiles_to_reconsider_zones = tiles_to_reconsider_alternate + tiles_to_reconsider_alternate = null + else + tiles_to_reconsider_zones = list() //Process zones. if(.) @@ -217,6 +237,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun Z.last_update = current_cycle if(. && Z && !output) . = 0 + //Process fires. if(.) tick_progress = "active_hotspots (fire)" @@ -246,4 +267,33 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun else tiles_to_update_alternate |= tiles_to_check else - tiles_to_update |= tiles_to_check \ No newline at end of file + tiles_to_update |= tiles_to_check + + +/datum/controller/air_system/proc/AddConnectionToCheck(connection/connection) + if(checking_connections) + if(istype(connection, /list)) + if(!connections_to_check_alternate) + connections_to_check_alternate = connection + + else if(!connections_to_check_alternate) + connections_to_check_alternate = list() + + connections_to_check_alternate |= connection + + else + connections_to_check |= connection + + +/datum/controller/air_system/proc/ReconsiderTileZone(var/turf/simulated/zoneless_turf) + if(zoneless_turf.zone) + return + + if(reconsidering_zones) + if(!tiles_to_reconsider_alternate) + tiles_to_reconsider_alternate = list() + + tiles_to_reconsider_alternate |= zoneless_turf + + else + tiles_to_reconsider_zones |= zoneless_turf diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 9851eb2fa5..136a77118f 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -158,10 +158,9 @@ //Check pass sanity of the connections. if("\ref[src]" in air_master.turfs_with_connections) - for(var/connection/C in air_master.turfs_with_connections["\ref[src]"]) - air_master.connections_to_check |= C + air_master.AddConnectionToCheck(air_master.turfs_with_connections["\ref[src]"]) - if(zone && !zone.rebuild && CanPass(null, src, 0, 0)) + if(zone && CanPass(null, src, 0, 0)) for(var/direction in cardinal) var/turf/T = get_step(src,direction) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index a3667a0180..b2d68934f7 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -54,12 +54,11 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //Ensuring the zone list doesn't get clogged with null values. for(var/turf/simulated/T in contents) RemoveTurf(T) - air_master.tiles_to_reconsider_zones += T + air_master.ReconsiderTileZone(T) for(var/zone/Z in connected_zones) if(src in Z.connected_zones) Z.connected_zones.Remove(src) - for(var/connection/C in connections) - air_master.connections_to_check += C + air_master.AddConnectionToCheck(connections) zones.Remove(src) air = null . = ..() @@ -73,7 +72,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //Ensuring the zone list doesn't get clogged with null values. for(var/turf/simulated/T in contents) RemoveTurf(T) - air_master.tiles_to_reconsider_zones += T + air_master.ReconsiderTileZone(T) //Removing zone connections and scheduling connection cleanup for(var/zone/Z in connected_zones) @@ -81,8 +80,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs Z.connected_zones.Remove(src) connected_zones = null - for(var/connection/C in connections) - air_master.connections_to_check += C + air_master.AddConnectionToCheck(connections) connections = null return 1 diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 1a543381da..92170b0108 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -126,7 +126,6 @@ datum/controller/game_controller/proc/process() timer = world.timeofday last_thing_processed = air_master.type - air_master.current_cycle++ if(!air_master.Tick()) //Runtimed. air_master.failed_ticks++ if(air_master.failed_ticks > 5) @@ -136,7 +135,8 @@ datum/controller/game_controller/proc/process() log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]") air_processing_killed = 1 air_master.failed_ticks = 0 - air_cost = (world.timeofday - timer) / 10 + + air_cost = (world.timeofday - timer) / 10 sleep(breather_ticks) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 22d9c1a0b6..60799f618e 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -318,7 +318,7 @@ /obj/structure/window/proc/update_nearby_tiles(need_rebuild) if(!air_master) return 0 - AddTurfToUpdate( + air_master.AddTurfToUpdate(get_turf(src)) return 1 diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index dc15cc4c9d..1a5675609c 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -231,8 +231,8 @@ W.zone = src.zone W.zone.AddTurf(W) - for(var/turf/simulated/T in orange(src,1)) - air_master.tiles_to_update.Add(T) + if(air_master) + air_master.AddTurfToUpdate(src) W.levelupdate() return W @@ -252,8 +252,7 @@ W.zone.AddTurf(W) if(air_master) - for(var/turf/simulated/T in orange(src,1)) - air_master.tiles_to_update.Add(T) + air_master.AddTurfToUpdate(src) W.levelupdate() return W diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 355fe221fc..ef4eb53170 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -580,11 +580,11 @@ var/list/admin_verbs_mod = list( set category = "Debug" set name = "Kill Air" set desc = "Toggle Air Processing" - if(kill_air) - kill_air = 0 + if(air_processing_killed) + air_processing_killed = 0 usr << "Enabled air processing." else - kill_air = 1 + air_processing_killed = 1 usr << "Disabled air processing." feedback_add_details("admin_verb","KA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] used 'kill air'.") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index af7f4f545e..9872c5e5a0 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -161,6 +161,7 @@ var/intercom_range_display_status = 0 src.verbs += /client/proc/disable_movement src.verbs += /client/proc/Zone_Info src.verbs += /client/proc/Test_ZAS_Connection + src.verbs += /client/proc/ZoneTick //src.verbs += /client/proc/cmd_admin_rejuvenate feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! From 3b2da3238cb493e16e06590ab1e8cbf3bcda04a0 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 15:41:50 -0700 Subject: [PATCH 3/9] Reduces processing of connections, zones now rely on the air properties of constituent turfs (they will adjust these properties when turfs are added or removed) --- code/ZAS/Connection.dm | 150 ++++++++++++++++++++++++++--------------- code/ZAS/FEA_system.dm | 24 +++---- code/ZAS/Functions.dm | 9 ++- code/ZAS/ZAS_Turfs.dm | 4 +- code/ZAS/ZAS_Zones.dm | 148 ++++++++++++++++++---------------------- 5 files changed, 180 insertions(+), 155 deletions(-) diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm index 8a919d5043..7f020e551c 100644 --- a/code/ZAS/Connection.dm +++ b/code/ZAS/Connection.dm @@ -13,68 +13,62 @@ Indirect connections will not merge the two zones after they reach equilibrium. var/zone/zone_A var/zone/zone_B - var/ref_A - var/ref_B - var/indirect = CONNECTION_DIRECT //If the connection is purely indirect, the zones should not join. - var/last_updated //The tick at which this was last updated. - - var/no_zone_count = 0 - - /connection/New(turf/T,turf/O) + . = ..() + A = T B = O + if(A.zone && B.zone) - if(!A.zone.connections) A.zone.connections = list() + if(!A.zone.connections) + A.zone.connections = list() A.zone.connections += src zone_A = A.zone - ref_A = "\ref[A]" - if(!B.zone.connections) B.zone.connections = list() + if(!B.zone.connections) + B.zone.connections = list() B.zone.connections += src zone_B = B.zone - ref_B = "\ref[B]" - if(ref_A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_A] + if(A in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[A] connections.Add(src) else - air_master.turfs_with_connections[ref_A] = list(src) + air_master.turfs_with_connections[A] = list(src) - if(ref_B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_B] + if(B in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[B] connections.Add(src) else - air_master.turfs_with_connections[ref_B] = list(src) + air_master.turfs_with_connections[B] = list(src) if(A.CanPass(null, B, 0, 0)) - ConnectZones(A.zone, B.zone, 1) - - if(A.HasDoor(B) || B.HasDoor(A)) + if(!A.CanPass(null, B, 1.5, 1)) indirect = CONNECTION_INDIRECT + ConnectZones(A.zone, B.zone, indirect) + else ConnectZones(A.zone, B.zone) indirect = CONNECTION_CLOSED - else world.log << "Attempted to create connection object for non-zone tiles: [T] ([T.x],[T.y],[T.z]) -> [O] ([O.x],[O.y],[O.z])" - del(src) + SoftDelete() /connection/Del() //remove connections from master lists. - if(ref_B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_B] + if(B in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[B] connections.Remove(src) - if(ref_A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_A] + if(A in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[A] connections.Remove(src) //Remove connection from zones. @@ -104,13 +98,52 @@ Indirect connections will not merge the two zones after they reach equilibrium. //Disconnect zones while handling unusual conditions. // e.g. loss of a zone on a turf - if(A && A.zone && B && B.zone) - DisconnectZones(A.zone, B.zone) + DisconnectZones(zone_A, zone_B) //Finally, preform actual deletion. . = ..() +/connection/proc/SoftDelete() + //remove connections from master lists. + if(B in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[B] + connections.Remove(src) + + if(A in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[A] + connections.Remove(src) + + //Remove connection from zones. + if(A) + if(A.zone && A.zone.connections) + A.zone.connections.Remove(src) + if(!A.zone.connections.len) + A.zone.connections = null + + if(istype(zone_A) && (!A || A.zone != zone_A)) + if(zone_A.connections) + zone_A.connections.Remove(src) + if(!zone_A.connections.len) + zone_A.connections = null + + if(B) + if(B.zone && B.zone.connections) + B.zone.connections.Remove(src) + if(!B.zone.connections.len) + B.zone.connections = null + + if(istype(zone_B) && (!B || B.zone != zone_B)) + if(zone_B.connections) + zone_B.connections.Remove(src) + if(!zone_B.connections.len) + zone_B.connections = null + + //Disconnect zones while handling unusual conditions. + // e.g. loss of a zone on a turf + DisconnectZones(zone_A, zone_B) + + /connection/proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0) //Sanity checking @@ -140,6 +173,18 @@ Indirect connections will not merge the two zones after they reach equilibrium. zone_2.connected_zones += zone_1 zone_2.connected_zones[zone_1] = 1 + if(open == CONNECTION_DIRECT) + if(!zone_1.direct_connections) + zone_1.direct_connections = list(src) + else + zone_1.direct_connections += src + + if(!zone_2.direct_connections) + zone_2.direct_connections = list(src) + else + zone_2.direct_connections += src + + //Handle closed connections. else @@ -193,6 +238,15 @@ Indirect connections will not merge the two zones after they reach equilibrium. if(!zone_2.connected_zones.len) zone_2.connected_zones = null + if(indirect == CONNECTION_DIRECT) + zone_1.direct_connections -= src + if(!zone_1.direct_connections.len) + zone_1.direct_connections = null + + zone_2.direct_connections -= src + if(!zone_2.direct_connections.len) + zone_2.direct_connections = null + else //Handle disconnection of closed zones. if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) ) @@ -222,35 +276,23 @@ Indirect connections will not merge the two zones after they reach equilibrium. //Check sanity: existance of turfs if(!A || !B) - del src + SoftDelete() + return + + //Check sanity: loss of zone + if(!A.zone || !B.zone) + SoftDelete() + return //Check sanity: zones are different if(A.zone == B.zone) - del src - - //Check sanity: same turfs as before. - if(ref_A != "\ref[A]" || ref_B != "\ref[B]") - del src + SoftDelete() + return //Handle zones changing on a turf. if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B)) Sanitize() - //Manage sudden loss of a turfs zone. (e.g. a wall being built) - if(!A.zone || !B.zone) - no_zone_count++ - if(no_zone_count >= 5) - //world.log << "Connection removed: [A] or [B] missing a zone." - del src - return 0 - - return 1 - - -/connection/proc/CheckPassSanity() - //Sanity check, first. - Cleanup() - if(A.zone && B.zone) //If no walls are blocking us... @@ -263,7 +305,7 @@ Indirect connections will not merge the two zones after they reach equilibrium. //Make and remove connections to let air pass. if(indirect == CONNECTION_CLOSED) DisconnectZones(A.zone, B.zone) - ConnectZones(A.zone, B.zone, 1) + ConnectZones(A.zone, B.zone, door_pass + 1) if(door_pass) indirect = CONNECTION_DIRECT @@ -278,7 +320,8 @@ Indirect connections will not merge the two zones after they reach equilibrium. //If I can no longer pass air, better delete else - del src + SoftDelete() + return /connection/proc/Sanitize() //If the zones change on connected turfs, update it. @@ -294,9 +337,6 @@ Indirect connections will not merge the two zones after they reach equilibrium. A = temp zone_B = B.zone zone_A = A.zone - var/temp_ref = ref_A - ref_A = ref_B - ref_B = temp_ref return //Handle removal of connections from archived zones. diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm index 0f5351ce1b..508cbb0125 100644 --- a/code/ZAS/FEA_system.dm +++ b/code/ZAS/FEA_system.dm @@ -199,7 +199,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun checking_connections = TRUE for(var/connection/C in connections_to_check) - C.CheckPassSanity() + C.Cleanup() checking_connections = FALSE @@ -209,6 +209,17 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun else connections_to_check = list() + //Process zones. + if(.) + tick_progress = "zone/process()" + for(var/zone/Z in zones) + if(Z.last_update < current_cycle) + var/output = Z.process() + if(Z) + Z.last_update = current_cycle + if(. && Z && !output) + . = 0 + //Ensure tiles still have zones. if(.) tick_progress = "tiles_to_reconsider_zones" @@ -227,17 +238,6 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun else tiles_to_reconsider_zones = list() - //Process zones. - if(.) - tick_progress = "zone/process()" - for(var/zone/Z in zones) - if(Z.last_update < current_cycle) - var/output = Z.process() - if(Z) - Z.last_update = current_cycle - if(. && Z && !output) - . = 0 - //Process fires. if(.) tick_progress = "active_hotspots (fire)" diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm index ce24513418..87bc9e3496 100644 --- a/code/ZAS/Functions.dm +++ b/code/ZAS/Functions.dm @@ -157,14 +157,13 @@ proc/ZConnect(turf/simulated/A,turf/simulated/B) if(!A.zone || !B.zone) return if(A.zone == B.zone) return - if(A.CanPass(null,B,0,1)) + if(A.zone.air.compare(B.zone.air)) return ZMerge(A.zone,B.zone) //Ensure the connection isn't already made. - if("\ref[A]" in air_master.turfs_with_connections) - for(var/connection/C in air_master.turfs_with_connections["\ref[A]"]) - C.Cleanup() - if(C && (C.B == B || C.A == B)) + if(A in air_master.turfs_with_connections) + for(var/connection/C in air_master.turfs_with_connections[A]) + if(C.B == B || C.A == B) return //Make the connection. diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 136a77118f..b329b488cb 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -157,8 +157,8 @@ new/zone(list(src)) //Check pass sanity of the connections. - if("\ref[src]" in air_master.turfs_with_connections) - air_master.AddConnectionToCheck(air_master.turfs_with_connections["\ref[src]"]) + if(src in air_master.turfs_with_connections) + air_master.AddConnectionToCheck(air_master.turfs_with_connections[src]) if(zone && CanPass(null, src, 0, 0)) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index b2d68934f7..92e73a8d58 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -7,11 +7,15 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs var/rebuild = 0 //If 1, zone will be rebuilt on next process. Not sure if used. var/datum/gas_mixture/air //The air contents of the zone. var/list/contents //All the tiles that are contained in this zone. - var/list/connections // /connection objects which refer to connections with other zones, e.g. through a door. - var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number - //of points they're connected at. - var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed. var/list/unsimulated_tiles // Any space tiles in this list will cause air to flow out. + + var/list/connections //connection objects which refer to connections with other zones, e.g. through a door. + var/list/direct_connections //connections which directly connect two zones. + + var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number + //of points they're connected at. + var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed. + var/last_update = 0 var/progress = "nothing" @@ -49,7 +53,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs zones.Add(src) - //LEGACY, DO NOT USE. Use the SoftDelete proc. +//DO NOT USE. Use the SoftDelete proc. /zone/Del() //Ensuring the zone list doesn't get clogged with null values. for(var/turf/simulated/T in contents) @@ -64,7 +68,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs . = ..() - //Handles deletion via garbage collection. +//Handles deletion via garbage collection. /zone/proc/SoftDelete() zones.Remove(src) air = null @@ -96,8 +100,15 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs T.zone.RemoveTurf(T) contents += T if(air) + air.oxygen = (air.oxygen * air.group_multiplier + T.oxygen) / (air.group_multiplier + 1) + air.nitrogen = (air.nitrogen * air.group_multiplier + T.nitrogen) / (air.group_multiplier + 1) + air.carbon_dioxide = (air.carbon_dioxide * air.group_multiplier + T.carbon_dioxide) / (air.group_multiplier + 1) + air.toxins = (air.toxins * air.group_multiplier + T.toxins) / (air.group_multiplier + 1) + air.temperature = (air.temperature * air.group_multiplier + T.temperature) / (air.group_multiplier + 1) air.group_multiplier++ + T.zone = src + else if(!unsimulated_tiles) unsimulated_tiles = list() @@ -113,9 +124,19 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs return contents -= T if(air) + T.oxygen = air.oxygen + T.nitrogen = air.nitrogen + T.carbon_dioxide = air.carbon_dioxide + T.toxins = air.toxins + T.temperature = air.temperature air.group_multiplier-- + if(T.zone == src) T.zone = null + + if(!contents.len) + SoftDelete() + else if(unsimulated_tiles) unsimulated_tiles -= T if(!unsimulated_tiles.len) @@ -224,17 +245,13 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs progress = "problem with: ZMerge(), a couple of misc procs" - for(var/connection/C in connections) - //Check if the connection is valid first. - if(!C.Cleanup()) - continue + if(length(direct_connections)) + for(var/connection/C in connections) - //Do merging if conditions are met. Specifically, if there's a non-door connection - //to somewhere with space, the zones are merged regardless of equilibrium, to speed - //up spacing in areas with double-plated windows. - if(C && C.A.zone && C.B.zone) - //indirect = 2 is a direct connection. - if( C.indirect == 2 ) + //Do merging if conditions are met. Specifically, if there's a non-door connection + //to somewhere with space, the zones are merged regardless of equilibrium, to speed + //up spacing in areas with double-plated windows. + if(C.A.zone && C.B.zone) if(C.A.zone.air.compare(C.B.zone.air) || unsimulated_tiles) ZMerge(C.A.zone,C.B.zone) @@ -264,6 +281,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //If that zone has already processed, skip it. if(Z.last_update > last_update) continue + if(air && Z.air) if( abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta ) ShareHeat(air, Z.air, closed_connection_zones[Z]) @@ -455,69 +473,45 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) zone/proc/Rebuild() //Choose a random turf and regenerate the zone from it. - var - turf/simulated/sample = locate() in contents - list/new_contents - problem = 0 + var/list/new_contents + var/list/new_unsimulated - // - var/list/turfs_to_consider = contents.Copy() + var/list/turfs_needing_zones = list() - while(!sample || !sample.CanPass(null, sample, 1.5, 1)) - if(sample) - turfs_to_consider.Remove(sample) - sample = locate() in turfs_to_consider - if(!sample) - break + var/list/zones_to_check_connections = list(src) - if(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1)) //Not a single valid turf. - for(var/turf/simulated/T in contents) - air_master.tiles_to_update |= T + if(!locate(/turf/simulated/floor) in contents) + for(var/turf/simulated/turf in contents) + air_master.ReconsiderTileZone(turf) return SoftDelete() - new_contents = FloodFill(sample) + new_contents = FloodFill(locate(/turf/simulated/floor) in contents) - var/list/new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() ) + new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() ) + //Now, we have allocated the new turfs into proper lists, and we can start actually rebuilding. + + //If something isn't carried over, it will need a new zone. + for(var/turf/T in contents) + if(!(T in new_contents)) + RemoveTurf(T) + turfs_needing_zones += T + + //Handle addition of new turfs for(var/turf/S in new_contents) if(!istype(S, /turf/simulated)) new_unsimulated |= S new_contents.Remove(S) - if(contents.len != new_contents.len) - problem = 1 + //If something new is added, we need to deal with it seperately. + else if(!(S in contents) && istype(S, /turf/simulated)) + if(!(S.zone in zones_to_check_connections)) + zones_to_check_connections += S.zone - //If something isn't carried over, there was a complication. - for(var/turf/T in contents) - if(!(T in new_contents)) - T.zone = null - problem = 1 + S.zone.RemoveTurf(S) + AddTurf(S) - if(problem) - //Build some new zones for stuff that wasn't included. - var/list/turf/simulated/rebuild_turfs = contents - new_contents - var/list/turf/simulated/reconsider_turfs = list() - contents = new_contents - for(var/turf/simulated/T in rebuild_turfs) - if(!T.zone && T.CanPass(null, T, 1.5, 1)) - var/zone/Z = new /zone(T) - Z.air.copy_from(air) - else - reconsider_turfs |= T - for(var/turf/simulated/T in reconsider_turfs) - if(!T.zone && T.CanPass(null, T, 1.5, 1)) - var/zone/Z = new /zone(T) - Z.air.copy_from(air) - else if(!T in air_master.tiles_to_update) - air_master.tiles_to_update.Add(T) - - for(var/turf/simulated/T in contents) - if(T.zone && T.zone != src) - T.zone.RemoveTurf(T) - T.zone = src - else if(!T.zone) - T.zone = src - air.group_multiplier = contents.len + //Handle the addition of new unsimulated tiles. unsimulated_tiles = null if(new_unsimulated.len) @@ -529,20 +523,12 @@ zone/proc/Rebuild() if(istype(T) && T.zone && S.CanPass(null, T, 0, 0)) T.zone.AddTurf(S) -//UNUSED -/* -zone/proc/connected_zones() - //A legacy proc for getting connected zones. - . = list() - for(var/connection/C in connections) - var/zone/Z - if(C.A.zone == src) - Z = C.B.zone - else - Z = C.A.zone + //Finally, handle the orphaned turfs - if(Z in .) - .[Z]++ - else - . += Z - .[Z] = 1*/ + for(var/turf/simulated/T in turfs_needing_zones) + if(!T.zone) + zones_to_check_connections += new /zone(T) + + for(var/zone/zone in zones_to_check_connections) + for(var/connection/C in zone.connections) + C.Cleanup() From 5eb87a8b138df049508fb155ca9548a2b133e4d6 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 19:10:29 -0700 Subject: [PATCH 4/9] Use of two-pass connected component labeling to improve zone rebuilding Signed-off-by: SkyMarshal --- code/ZAS/Functions.dm | 4 +- code/ZAS/ZAS_Zones.dm | 115 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm index 87bc9e3496..316e7c18e2 100644 --- a/code/ZAS/Functions.dm +++ b/code/ZAS/Functions.dm @@ -2,7 +2,7 @@ //Contents: FloodFill, ZMerge, ZConnect //Floods outward from an initial turf to fill everywhere it's zone would reach. -proc/FloodFill(turf/simulated/start) +proc/FloodFill(turf/simulated/start, var/list/turfs_to_skip = list()) if(!istype(start)) return list() @@ -10,7 +10,7 @@ proc/FloodFill(turf/simulated/start) //The list of tiles waiting to be evaulated. var/list/open = list(start) //The list of tiles which have been evaulated. - var/list/closed = list() + var/list/closed = turfs_to_skip //Loop through the turfs in the open list in order to find which adjacent turfs should be added to the zone. while(open.len) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index 92e73a8d58..40a101fd2c 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -100,11 +100,6 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs T.zone.RemoveTurf(T) contents += T if(air) - air.oxygen = (air.oxygen * air.group_multiplier + T.oxygen) / (air.group_multiplier + 1) - air.nitrogen = (air.nitrogen * air.group_multiplier + T.nitrogen) / (air.group_multiplier + 1) - air.carbon_dioxide = (air.carbon_dioxide * air.group_multiplier + T.carbon_dioxide) / (air.group_multiplier + 1) - air.toxins = (air.toxins * air.group_multiplier + T.toxins) / (air.group_multiplier + 1) - air.temperature = (air.temperature * air.group_multiplier + T.temperature) / (air.group_multiplier + 1) air.group_multiplier++ T.zone = src @@ -124,11 +119,6 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs return contents -= T if(air) - T.oxygen = air.oxygen - T.nitrogen = air.nitrogen - T.carbon_dioxide = air.carbon_dioxide - T.toxins = air.toxins - T.temperature = air.temperature air.group_multiplier-- if(T.zone == src) @@ -470,8 +460,102 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) /////////////////// //Zone Rebuilding// /////////////////// +//Used for updating zone geometry when a zone is cut into two parts. zone/proc/Rebuild() + var/list/new_zone_contents = IsolateContents() + if(new_zone_contents.len == 1) + return + + var/list/current_contents + var/list/new_zones = list() + + contents = new_zone_contents[1] + air.group_multiplier = contents.len + + for(var/identifier in 2 to new_zone_contents.len) + current_contents = new_zone_contents[identifier] + var/zone/new_zone = new (current_contents) + new_zone.air.copy_from(air) + new_zones += new_zone + + for(var/connection/connection in connections) + connection.Cleanup() + + var/turf/simulated/adjacent + + for(var/turf/unsimulated in unsimulated_tiles) + for(var/direction in cardinal) + adjacent = get_step(unsimulated, direction) + + if(istype(adjacent) && adjacent.CanPass(null, unsimulated, 0, 0)) + for(var/zone/zone in new_zones) + if(adjacent in zone) + zone.AddTurf(unsimulated) + + +//Implements a two-pass connected component labeling algorithm to determine if the zone is, in fact, split. + +/zone/proc/IsolateContents() + var/turf/simulated/current + var/turf/simulated/adjacent + var/list/current_adjacents = list() + var/adjacent_id + var/lowest_id + + var/list/identical_ids = list() + var/turfs = contents.Copy() + var/current_identifier = 1 + + for(current in turfs) + lowest_id = null + current_adjacents = list() + + for(var/direction in current.air_check_directions) + adjacent = get_step(current, direction) + if(adjacent in turfs) + current_adjacents += adjacent + adjacent_id = turfs[adjacent] + + if(adjacent_id && (!lowest_id || adjacent_id < lowest_id)) + lowest_id = adjacent_id + + if(!lowest_id) + lowest_id = current_identifier++ + + for(adjacent in current_adjacents) + adjacent_id = turfs[adjacent] + if(adjacent_id) + if(identical_ids.len < adjacent_id) + identical_ids.len = adjacent_id + + identical_ids[adjacent_id] = lowest_id + + turfs[adjacent] = lowest_id + turfs[current] = lowest_id + + var/list/final_arrangement = list() + + for(current in turfs) + current_identifier = identical_ids[turfs[current]] + + if( current_identifier > final_arrangement.len ) + final_arrangement.len = current_identifier + final_arrangement[current_identifier] = list(current) + + else + final_arrangement[current_identifier] += current + + //lazy but fast + final_arrangement.Remove(null) + + return final_arrangement + + +/* + if(!RequiresRebuild()) + return + //Choose a random turf and regenerate the zone from it. var/list/new_contents var/list/new_unsimulated @@ -485,7 +569,13 @@ zone/proc/Rebuild() air_master.ReconsiderTileZone(turf) return SoftDelete() - new_contents = FloodFill(locate(/turf/simulated/floor) in contents) + var/turfs_to_ignore = list() + if(direct_connections) + for(var/connection/connection in direct_connections) + if(connection.A.zone != src) + turfs_to_ignore += A + else if(connection.B.zone != src) + turfs_to_ignore += B new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() ) @@ -531,4 +621,5 @@ zone/proc/Rebuild() for(var/zone/zone in zones_to_check_connections) for(var/connection/C in zone.connections) - C.Cleanup() + C.Cleanup()*/ + From 057c8eeacd1961c8d12ce1dd94cb3304b3211e3d Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 19:46:48 -0700 Subject: [PATCH 5/9] Fixed a minor derp. --- code/ZAS/ZAS_Zones.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index 40a101fd2c..b51c5fbd69 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -236,7 +236,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs progress = "problem with: ZMerge(), a couple of misc procs" if(length(direct_connections)) - for(var/connection/C in connections) + for(var/connection/C in direct_connections) //Do merging if conditions are met. Specifically, if there's a non-door connection //to somewhere with space, the zones are merged regardless of equilibrium, to speed From 1762c656403e94b8e2c55e956b4a539c2c17b4f3 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 19:57:55 -0700 Subject: [PATCH 6/9] man I am bad at this --- code/ZAS/Functions.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm index 316e7c18e2..2b38abb228 100644 --- a/code/ZAS/Functions.dm +++ b/code/ZAS/Functions.dm @@ -2,7 +2,7 @@ //Contents: FloodFill, ZMerge, ZConnect //Floods outward from an initial turf to fill everywhere it's zone would reach. -proc/FloodFill(turf/simulated/start, var/list/turfs_to_skip = list()) +proc/FloodFill(turf/simulated/start) if(!istype(start)) return list() @@ -10,7 +10,7 @@ proc/FloodFill(turf/simulated/start, var/list/turfs_to_skip = list()) //The list of tiles waiting to be evaulated. var/list/open = list(start) //The list of tiles which have been evaulated. - var/list/closed = turfs_to_skip + var/list/closed = list() //Loop through the turfs in the open list in order to find which adjacent turfs should be added to the zone. while(open.len) @@ -157,7 +157,7 @@ proc/ZConnect(turf/simulated/A,turf/simulated/B) if(!A.zone || !B.zone) return if(A.zone == B.zone) return - if(A.zone.air.compare(B.zone.air)) + if(A.CanPass(null, B, 0, 0) && A.zone.air.compare(B.zone.air)) return ZMerge(A.zone,B.zone) //Ensure the connection isn't already made. From 7d0c1f047a9e8ecbf8b3bb64bf811b3ec9b4f7af Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 21:03:46 -0700 Subject: [PATCH 7/9] There we go, rebuilding works right now. Also has a slightly bugged verb that demonstrates how the rebuilding works, but you need to somehow prevent a zone from updating for it to show more than one "id" --- code/ZAS/Debug.dm | 79 +++++++++++++++++++++++++++++ code/ZAS/Functions.dm | 2 +- code/ZAS/ZAS_Zones.dm | 28 +++++----- code/modules/admin/verbs/mapping.dm | 1 + 4 files changed, 94 insertions(+), 16 deletions(-) diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index 69047b56b6..b2a2f4c9e5 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -131,3 +131,82 @@ zone/proc/DebugDisplay(client/client) var/turf/zloc = pick(Z.contents) client << "\red Illegal air datum shared by: [zloc.loc.name]" + +client/proc/TestZASRebuild() +// var/turf/turf = get_turf(mob) + var/zone/current_zone = mob.loc:zone + if(!current_zone) + src << "There is no zone there!" + return + + var/list/current_adjacents = list() + var/list/overlays = list() + var/adjacent_id + var/lowest_id + + var/list/identical_ids = list() + var/list/turfs = current_zone.contents.Copy() + var/current_identifier = 1 + + src << "[turfs[1]] = [turfs[turfs[1]]]" + + for(var/turf/simulated/current in turfs) + lowest_id = null + current_adjacents = list() + + for(var/direction in cardinal) + if( !(current.air_check_directions & direction)) + continue + var/turf/simulated/adjacent = get_step(current, direction) + if(turfs.Find(adjacent)) + current_adjacents += adjacent + adjacent_id = turfs[adjacent] + + if(adjacent_id && (!lowest_id || adjacent_id < lowest_id)) + lowest_id = adjacent_id + + if(!lowest_id) + lowest_id = current_identifier++ + identical_ids += lowest_id + overlays += image('icons/misc/debug_rebuild.dmi',, "[lowest_id]") + + for(var/turf/simulated/adjacent in current_adjacents) + adjacent_id = turfs[adjacent] + if(adjacent_id != lowest_id) + if(adjacent_id) + adjacent.overlays -= overlays[adjacent_id] + identical_ids[adjacent_id] = lowest_id + + turfs[adjacent] = lowest_id + adjacent.overlays += overlays[lowest_id] + + sleep(5) + + turfs[current] = lowest_id + current.overlays += overlays[lowest_id] + sleep(5) + + var/list/final_arrangement = list() + + for(var/turf/simulated/current in turfs) + current_identifier = identical_ids[turfs[current]] + current.overlays -= overlays[turfs[current]] + current.overlays += overlays[current_identifier] + sleep(5) + + if( current_identifier > final_arrangement.len ) + final_arrangement.len = current_identifier + final_arrangement[current_identifier] = list(current) + + else + final_arrangement[current_identifier] += current + + //lazy but fast + final_arrangement.Remove(null) + + src << final_arrangement.len + + for(var/turf/current in turfs) + current.overlays -= overlays + + return final_arrangement diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm index 2b38abb228..4a1ffaaea2 100644 --- a/code/ZAS/Functions.dm +++ b/code/ZAS/Functions.dm @@ -157,7 +157,7 @@ proc/ZConnect(turf/simulated/A,turf/simulated/B) if(!A.zone || !B.zone) return if(A.zone == B.zone) return - if(A.CanPass(null, B, 0, 0) && A.zone.air.compare(B.zone.air)) + if(A.CanPass(null, B, 1.5, 1) && A.zone.air.compare(B.zone.air)) return ZMerge(A.zone,B.zone) //Ensure the connection isn't already made. diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index b51c5fbd69..37aabee83b 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -497,22 +497,22 @@ zone/proc/Rebuild() //Implements a two-pass connected component labeling algorithm to determine if the zone is, in fact, split. /zone/proc/IsolateContents() - var/turf/simulated/current - var/turf/simulated/adjacent var/list/current_adjacents = list() var/adjacent_id var/lowest_id var/list/identical_ids = list() - var/turfs = contents.Copy() + var/list/turfs = contents.Copy() var/current_identifier = 1 - for(current in turfs) + for(var/turf/simulated/current in turfs) lowest_id = null current_adjacents = list() - for(var/direction in current.air_check_directions) - adjacent = get_step(current, direction) + for(var/direction in cardinal) + if( !(current.air_check_directions & direction)) + continue + var/turf/simulated/adjacent = get_step(current, direction) if(adjacent in turfs) current_adjacents += adjacent adjacent_id = turfs[adjacent] @@ -522,21 +522,19 @@ zone/proc/Rebuild() if(!lowest_id) lowest_id = current_identifier++ + identical_ids += lowest_id - for(adjacent in current_adjacents) + for(var/turf/simulated/adjacent in current_adjacents) adjacent_id = turfs[adjacent] - if(adjacent_id) - if(identical_ids.len < adjacent_id) - identical_ids.len = adjacent_id - - identical_ids[adjacent_id] = lowest_id - - turfs[adjacent] = lowest_id + if(adjacent_id != lowest_id) + if(adjacent_id) + identical_ids[adjacent_id] = lowest_id + turfs[adjacent] = lowest_id turfs[current] = lowest_id var/list/final_arrangement = list() - for(current in turfs) + for(var/turf/simulated/current in turfs) current_identifier = identical_ids[turfs[current]] if( current_identifier > final_arrangement.len ) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 9872c5e5a0..76f1b42046 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -162,6 +162,7 @@ var/intercom_range_display_status = 0 src.verbs += /client/proc/Zone_Info src.verbs += /client/proc/Test_ZAS_Connection src.verbs += /client/proc/ZoneTick + src.verbs += /client/proc/TestZASRebuild //src.verbs += /client/proc/cmd_admin_rejuvenate feedback_add_details("admin_verb","mDV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! From 301de25baedbea94346c999e24c8619f09f7f581 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 21:07:34 -0700 Subject: [PATCH 8/9] Fixes the not-considering-actual-geometry issue. --- code/ZAS/Debug.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index b2a2f4c9e5..874ae50a12 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -155,9 +155,9 @@ client/proc/TestZASRebuild() current_adjacents = list() for(var/direction in cardinal) - if( !(current.air_check_directions & direction)) - continue var/turf/simulated/adjacent = get_step(current, direction) + if(!current.ZAirPass(adjacent)) + continue if(turfs.Find(adjacent)) current_adjacents += adjacent adjacent_id = turfs[adjacent] From 9c879608520283101ed554c490e8d4a977f334aa Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 21:11:46 -0700 Subject: [PATCH 9/9] Bluh. --- code/ZAS/Debug.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index 874ae50a12..762843d5b1 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -148,8 +148,6 @@ client/proc/TestZASRebuild() var/list/turfs = current_zone.contents.Copy() var/current_identifier = 1 - src << "[turfs[1]] = [turfs[turfs[1]]]" - for(var/turf/simulated/current in turfs) lowest_id = null current_adjacents = list() @@ -182,6 +180,8 @@ client/proc/TestZASRebuild() sleep(5) + if(turfs[current]) + current.overlays += overlays[turfs[current]] turfs[current] = lowest_id current.overlays += overlays[lowest_id] sleep(5) @@ -204,7 +204,7 @@ client/proc/TestZASRebuild() //lazy but fast final_arrangement.Remove(null) - src << final_arrangement.len + src << "There are [final_arrangement.len] unique segments." for(var/turf/current in turfs) current.overlays -= overlays