From 3b2da3238cb493e16e06590ab1e8cbf3bcda04a0 Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Fri, 6 Sep 2013 15:41:50 -0700 Subject: [PATCH] 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 8a919d50435..7f020e551c1 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 0f5351ce1ba..508cbb0125c 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 ce24513418e..87bc9e3496f 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 136a77118fd..b329b488cb4 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 b2d68934f76..92e73a8d581 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()