diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 167e664b87a..a48360803ba 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -1,7 +1,9 @@ SUBSYSTEM_DEF(mapping) name = "Mapping" init_order = INIT_ORDER_MAPPING - flags = NONE + flags = SS_NO_FIRE + + var/world_loaded = FALSE var/list/nuke_tiles = list() var/list/nuke_threats = list() @@ -25,7 +27,7 @@ SUBSYSTEM_DEF(mapping) var/list/datum/turf_reservations //list of turf reservations var/list/used_turfs = list() //list of turf = datum/turf_reservation - var/clearing_reserved_areas = FALSE + var/clearing_reserved_turfs = FALSE // Z-manager stuff var/station_start // should only be used for maploading-related tasks @@ -46,6 +48,8 @@ SUBSYSTEM_DEF(mapping) /datum/controller/subsystem/mapping/Initialize(timeofday) + if(initialized) + return if(config.defaulted) to_chat(world, "Unable to load next map config, defaulting to Box Station") loader = new @@ -96,9 +100,34 @@ SUBSYSTEM_DEF(mapping) Used by the AI doomsday and the self destruct nuke. */ -/datum/controller/subsystem/mapping/fire() - if(clearing_reserved_areas) - wipe_turf_reservations() +/datum/controller/subsystem/mapping/proc/wipe_reservations(wipe_safety_delay = 100) + if(clearing_reserved_turfs || !initialized) //in either case this is just not needed. + return + clearing_reserved_turfs = TRUE + SSshuttle.transit_requesters.Cut() + message_admins("Clearing dynamic reservation space.") + var/list/obj/docking_port/mobile/in_transit = list() + for(var/i in SSshuttle.transit) + var/obj/docking_port/stationary/transit/T = i + if(!istype(T)) + continue + in_transit[T] = T.get_docked() + var/go_ahead = world.time + wipe_safety_delay + if(in_transit.len) + message_admins("Shuttles in transit detected. Attempting to fast travel. Timeout is [go_ahead/10] seconds.") + var/list/cleared = list() + for(var/i in in_transit) + INVOKE_ASYNC(src, .proc/safety_clear_transit_dock, i, in_transit[i], cleared) + UNTIL((go_ahead < world.time) || (cleared.len == in_transit.len)) + do_wipe_turf_reservations() + clearing_reserved_turfs = FALSE + +/datum/controller/subsystem/mapping/proc/safety_clear_transit_dock(obj/docking_port/stationary/transit/T, obj/docking_port/mobile/M, list/returning) + M.setTimer(0) + var/error = M.initiate_docking(M.destination, M.preferred_direction) + if(!error) + returning += M + qdel(T, TRUE) /datum/controller/subsystem/mapping/proc/add_nuke_threat(datum/nuke) nuke_threats[nuke] = TRUE @@ -126,13 +155,13 @@ SUBSYSTEM_DEF(mapping) shuttle_templates = SSmapping.shuttle_templates shelter_templates = SSmapping.shelter_templates unused_turfs = SSmapping.unused_turfs - turf_reservations = SSmapping.turf_reservations. + turf_reservations = SSmapping.turf_reservations used_turfs = SSmapping.used_turfs config = SSmapping.config next_map_config = SSmapping.next_map_config - clearing_reserved_areas = SSmapping.clearing_reserved_areas + clearing_reserved_turfs = SSmapping.clearing_reserved_turfs z_list = SSmapping.z_list @@ -399,6 +428,7 @@ GLOBAL_LIST_EMPTY(the_station_areas) GLOB.the_gateway.wait = world.time /datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) + UNTIL(initialized && !clearing_reserved_turfs) var/datum/turf_reservation/reserve = new type if(turf_type_override) reserve.turf_type = turf_type_override @@ -415,12 +445,15 @@ GLOBAL_LIST_EMPTY(the_station_areas) return reserve QDEL_NULL(reserve) +//This is not for wiping reserved levels, use wipe_reservations() for that. /datum/controller/subsystem/mapping/proc/initialize_reserved_level() - // transit zone + UNTIL(!clearing_reserved_turfs) //regardless, lets add a check just in case. + clearing_reserved_turfs = TRUE //This operation will likely clear any existing reservations, so lets make sure nothing tries to make one while we're doing it. for(var/i in levels_by_trait(ZTRAIT_RESERVED)) var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,i)) var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,i)) reserve_turfs(block(A, B)) + clearing_reserved_turfs = FALSE /datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs) for(var/i in turfs) @@ -429,20 +462,21 @@ GLOBAL_LIST_EMPTY(the_station_areas) LAZYINITLIST(unused_turfs["[T.z]"]) unused_turfs["[T.z]"] |= T T.flags_1 |= UNUSED_RESERVATION_TURF_1 + CHECK_TICK -/datum/controller/subsystem/mapping/proc/wipe_turf_reservations() - if(SSshuttle && SSshuttle.transit_requesters) - SSshuttle.transit_requesters.Cut() +//DO NOT CALL THIS PROC DIRECTLY, CALL wipe_reservations(). +/datum/controller/subsystem/mapping/proc/do_wipe_turf_reservations() + UNTIL(initialized) //This proc is for AFTER init, before init turf reservations won't even exist and using this will likely break things. for(var/i in turf_reservations) var/datum/turf_reservation/TR = i - qdel(TR, TRUE) - var/list/clearing = list() - for(var/l in unused_turfs) - for(var/i in l) - clearing |= i - for(var/i in used_turfs) - clearing |= i - unused_turfs = list() - used_turfs = list() - reserve_turfs(clearing) + if(!QDELETED(TR)) + qdel(TR, TRUE) UNSETEMPTY(turf_reservations) + var/list/clearing = list() + for(var/l in unused_turfs) //unused_turfs is a assoc list by z = list(turfs) + if(islist(unused_turfs[l])) + clearing |= unused_turfs[l] + clearing |= used_turfs //used turfs is an associative list, BUT, reserve_turfs() can still handle it. If the code above works properly, this won't even be needed as the turfs would be freed already. + unused_turfs.Cut() + used_turfs.Cut() + reserve_turfs(clearing) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 77c98c0c5e7..1e656ae1eb7 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -106,18 +106,19 @@ SUBSYSTEM_DEF(shuttle) qdel(T, force=TRUE) CheckAutoEvac() - while(transit_requesters.len) - var/requester = popleft(transit_requesters) - var/success = generate_transit_dock(requester) - if(!success) // BACK OF THE QUEUE - transit_request_failures[requester]++ - if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) - transit_requesters += requester - else - var/obj/docking_port/mobile/M = requester - M.transit_failure() - if(MC_TICK_CHECK) - break + if(!SSmapping.clearing_reserved_turfs) + while(transit_requesters.len) + var/requester = popleft(transit_requesters) + var/success = generate_transit_dock(requester) + if(!success) // BACK OF THE QUEUE + transit_request_failures[requester]++ + if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) + transit_requesters += requester + else + var/obj/docking_port/mobile/M = requester + M.transit_failure() + if(MC_TICK_CHECK) + break /datum/controller/subsystem/shuttle/proc/CheckAutoEvac() if(emergencyNoEscape || emergencyNoRecall || !emergency || !SSticker.HasRoundStarted()) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index d5b08e97d0f..d34e1ebd422 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -968,11 +968,10 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) var/answer = alert("WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", "Really wipe dynamic turfs?", "YES", "NO") if(answer != "YES") return - SSmapping.clearing_reserved_areas = TRUE message_admins("[key_name_admin(src)] cleared dynamic transit space.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Clear Dynamic Transit") // If... log_admin("[key_name(src)] cleared dynamic transit space.") - + SSmapping.wipe_reservations() //this goes after it's logged, incase something horrible happens. /client/proc/toggle_medal_disable() set category = "Debug" diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 48985821ddc..fc8169f6d25 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -219,8 +219,10 @@ if(owner.assigned_transit == src) owner.assigned_transit = null owner = null - QDEL_NULL(reserved_area) - . = ..() + if(!QDELETED(reserved_area)) + qdel(reserved_area) + reserved_area = null + return ..() /obj/docking_port/mobile name = "shuttle"