From 68f04575ac53471b2b6d6b7dc49b32853ade9e23 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Wed, 8 Nov 2023 19:56:57 -0600 Subject: [PATCH] Genericises multi-dock prevention (#2358) ## About The Pull Request Expands docking ticket functionality to include validation based on if another docking ticket has been created for a specific port, hopefully preventing multiple ships attempting to dock at the same port simultaneously. Also a freebie of ensuring planets which are generating can't be interacted with and caused to load a second time, since that's icky. ## Why It's Good For The Game Bugs from multiple people docking to an overmap object at once are bad. ## Changelog :cl: add: There's a few more descriptive docking errors now. /:cl: --- code/controllers/subsystem/overmap.dm | 10 +++--- code/modules/overmap/_overmap_datum.dm | 21 ++++++++--- code/modules/overmap/docking_ticket.dm | 35 ++++++++++++++++++- code/modules/overmap/objects/dynamic_datum.dm | 10 ++++++ .../overmap/objects/outpost/outpost.dm | 9 +---- .../overmap/ships/controlled_ship_datum.dm | 2 ++ code/modules/shuttle/shuttle.dm | 2 ++ 7 files changed, 70 insertions(+), 19 deletions(-) diff --git a/code/controllers/subsystem/overmap.dm b/code/controllers/subsystem/overmap.dm index eb6ccfa3c7b4..de03f6a5a03e 100644 --- a/code/controllers/subsystem/overmap.dm +++ b/code/controllers/subsystem/overmap.dm @@ -262,7 +262,7 @@ SUBSYSTEM_DEF(overmap) var/datum/map_template/ruin/used_ruin = ispath(ruin_type) ? (new ruin_type) : ruin_type // name is random but PROBABLY unique - var/encounter_name = dynamic_datum.planet_name || "Dynamic Overmap Encounter #[rand(1111,9999)]-[rand(1111,9999)]" + var/encounter_name = dynamic_datum.planet_name || "\improper Uncharted Space [dynamic_datum.x]/[dynamic_datum.y]-[rand(1111, 9999)]" var/datum/map_zone/mapzone = SSmapping.create_map_zone(encounter_name) var/datum/virtual_level/vlevel = SSmapping.create_virtual_level( encounter_name, @@ -318,7 +318,7 @@ SUBSYSTEM_DEF(overmap) var/obj/docking_port/stationary/primary_dock = new(primary_docking_turf) primary_dock.dir = NORTH - primary_dock.name = "\improper Uncharted Space" + primary_dock.name = "[encounter_name] docking location #1" primary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT primary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG primary_dock.dheight = 0 @@ -327,7 +327,7 @@ SUBSYSTEM_DEF(overmap) var/obj/docking_port/stationary/secondary_dock = new(secondary_docking_turf) secondary_dock.dir = NORTH - secondary_dock.name = "\improper Uncharted Space" + secondary_dock.name = "[encounter_name] docking location #2" secondary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT secondary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG secondary_dock.dheight = 0 @@ -350,7 +350,7 @@ SUBSYSTEM_DEF(overmap) var/obj/docking_port/stationary/tertiary_dock = new(tertiary_docking_turf) tertiary_dock.dir = NORTH - tertiary_dock.name = "\improper Uncharted Space" + tertiary_dock.name = "[encounter_name] docking location #3" tertiary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT tertiary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG tertiary_dock.dheight = 0 @@ -359,7 +359,7 @@ SUBSYSTEM_DEF(overmap) var/obj/docking_port/stationary/quaternary_dock = new(quaternary_docking_turf) quaternary_dock.dir = NORTH - quaternary_dock.name = "\improper Uncharted Space" + quaternary_dock.name = "[encounter_name] docking location #4" quaternary_dock.height = RESERVE_DOCK_MAX_SIZE_SHORT quaternary_dock.width = RESERVE_DOCK_MAX_SIZE_LONG quaternary_dock.dheight = 0 diff --git a/code/modules/overmap/_overmap_datum.dm b/code/modules/overmap/_overmap_datum.dm index 0f4dfdb34078..076188f6ec58 100644 --- a/code/modules/overmap/_overmap_datum.dm +++ b/code/modules/overmap/_overmap_datum.dm @@ -38,6 +38,9 @@ /// The icon state the token will be set to on init. var/token_icon_state = "object" + /// The current docking ticket of this object, if any + var/datum/docking_ticket/current_docking_ticket + /datum/overmap/New(position, ...) SHOULD_NOT_OVERRIDE(TRUE) // Use [/datum/overmap/proc/Initialize] instead. if(!position) @@ -64,6 +67,8 @@ /datum/overmap/Destroy(force, ...) SSovermap.overmap_objects -= src + if(current_docking_ticket) + QDEL_NULL(current_docking_ticket) if(docked_to) docked_to.post_undocked() docked_to.contents -= src @@ -219,17 +224,20 @@ if(docked_to) CRASH("Overmap datum [src] tried to dock to [docked_to] when it is already docked to another overmap datum.") - if(docking) - return + if(docking || current_docking_ticket) + return "Already docking!" docking = TRUE var/datum/docking_ticket/ticket = dock_target.pre_docked(src) - if(!ticket || ticket.docking_error) + var/ticket_error = ticket?.docking_error + if(!ticket || ticket_error) + qdel(ticket) docking = FALSE - return ticket?.docking_error || "Unknown docking error!" + return ticket_error || "Unknown docking error!" if(!pre_dock(dock_target, ticket)) + qdel(ticket) docking = FALSE - return + return ticket_error start_dock(dock_target, ticket) @@ -289,6 +297,9 @@ dock_target.post_docked(src) docking = FALSE + //Clears the docking ticket from both sides + qdel(current_docking_ticket) + SEND_SIGNAL(src, COMSIG_OVERMAP_DOCK, dock_target) /** diff --git a/code/modules/overmap/docking_ticket.dm b/code/modules/overmap/docking_ticket.dm index f32ffde39716..4e6465043246 100644 --- a/code/modules/overmap/docking_ticket.dm +++ b/code/modules/overmap/docking_ticket.dm @@ -9,7 +9,40 @@ var/docking_error /datum/docking_ticket/New(_target_port, _issuer, _target, _docking_error) + docking_error = _docking_error + if(docking_error) + return + + if(!_target_port) + docking_error = "No target port specified!" + return target_port = _target_port + if(target_port.current_docking_ticket) + docking_error = "[target_port] is already being docked to!" + return + target_port.current_docking_ticket = src + + if(!_issuer) + docking_error = "No issuer overmap datum specified!" + return issuer = _issuer + + if(!_target) + docking_error = "No target overmap datum specified!" + return target = _target - docking_error = _docking_error + if(target.current_docking_ticket) + docking_error = "[target] is already docking!" + return + target.current_docking_ticket = src + + +/datum/docking_ticket/Destroy(force, ...) + if(target) + target.current_docking_ticket = null + target = null + if(target_port) + target_port.current_docking_ticket = null + target_port = null + + return ..() diff --git a/code/modules/overmap/objects/dynamic_datum.dm b/code/modules/overmap/objects/dynamic_datum.dm index c6f0ed4a193e..82b77b513469 100644 --- a/code/modules/overmap/objects/dynamic_datum.dm +++ b/code/modules/overmap/objects/dynamic_datum.dm @@ -27,6 +27,8 @@ var/ruin_type /// list of ruins and their target turf, indexed by name var/list/ruin_turfs + /// Whether or not the level is currently loading. + var/loading = FALSE /// The mapgenerator itself. SHOULD NOT BE NULL if the datum ever creates an encounter var/datum/map_generator/mapgen = /datum/map_generator/single_turf/space @@ -68,6 +70,8 @@ return get_turf(pick(reserve_docks)) /datum/overmap/dynamic/pre_docked(datum/overmap/ship/controlled/dock_requester) + if(loading) + return new /datum/docking_ticket(_docking_error = "[src] is currently being scanned for suitable docking locations by another ship. Please wait.") if(!load_level()) return new /datum/docking_ticket(_docking_error = "[src] cannot be docked to.") else @@ -177,15 +181,21 @@ return FALSE if(mapzone) return TRUE + + loading = TRUE log_shuttle("[src] [REF(src)] LEVEL_INIT") + // use the ruin type in template if it exists, or pick from ruin list if IT exists; otherwise null var/selected_ruin = template || (ruin_type ? pickweightAllowZero(SSmapping.ruin_types_probabilities[ruin_type]) : null) var/list/dynamic_encounter_values = SSovermap.spawn_dynamic_encounter(src, selected_ruin) if(!length(dynamic_encounter_values)) return FALSE + mapzone = dynamic_encounter_values[1] reserve_docks = dynamic_encounter_values[2] ruin_turfs = dynamic_encounter_values[3] + + loading = FALSE return TRUE /datum/overmap/dynamic/empty diff --git a/code/modules/overmap/objects/outpost/outpost.dm b/code/modules/overmap/objects/outpost/outpost.dm index 589787a15c72..2d493a12b64a 100644 --- a/code/modules/overmap/objects/outpost/outpost.dm +++ b/code/modules/overmap/objects/outpost/outpost.dm @@ -33,9 +33,6 @@ /// The mapzone used by the outpost level and hangars. Using a single mapzone means networked radio messages. var/datum/map_zone/mapzone var/list/datum/hangar_shaft/shaft_datums = list() - /// A list keeping track of the docks that're currently being landed at. Helps to prevent SGTs, - /// as at time of writing there's no protection against a ship docking with a port that's already being docked to. - var/list/landing_in_progress_docks = list() // TODO: generalize this approach to prevent simultaneous-dock ship-overlap SGTs /// The maximum number of missions that may be offered by the outpost at one time. /// Missions which have been accepted do not count against this limit. @@ -214,14 +211,10 @@ ) return FALSE - landing_in_progress_docks += h_dock adjust_dock_to_shuttle(h_dock, dock_requester.shuttle_port) return new /datum/docking_ticket(h_dock, src, dock_requester) /datum/overmap/outpost/post_docked(datum/overmap/ship/controlled/dock_requester) - // removes the stationary dock from the list, so that we don't have to worry about it causing merge SGTs - landing_in_progress_docks -= dock_requester.shuttle_port.docked - for(var/mob/M as anything in GLOB.player_list) if(dock_requester.shuttle_port.is_in_shuttle_bounds(M)) M.play_screen_text("[name]
[station_time_timestamp_fancy("hh:mm")]") @@ -288,7 +281,7 @@ // a dock/undock cycle may leave the stationary port w/ flipped width and height, // due to adjust_dock_to_shuttle(). so we need to check both orderings of the list. if( \ - !(h_dock in landing_in_progress_docks) && !h_dock.docked && \ + !h_dock.current_docking_ticket && !h_dock.docked && \ ( \ (h_dock.width == h_template.dock_width && h_dock.height == h_template.dock_height) || \ (h_dock.width == h_template.dock_height && h_dock.height == h_template.dock_width) \ diff --git a/code/modules/overmap/ships/controlled_ship_datum.dm b/code/modules/overmap/ships/controlled_ship_datum.dm index cfdf87d44bdd..5b9638498285 100644 --- a/code/modules/overmap/ships/controlled_ship_datum.dm +++ b/code/modules/overmap/ships/controlled_ship_datum.dm @@ -139,8 +139,10 @@ /datum/overmap/ship/controlled/pre_dock(datum/overmap/to_dock, datum/docking_ticket/ticket) if(ticket.target != src || ticket.issuer != to_dock) + ticket.docking_error = "Invalid target." return FALSE if(!shuttle_port.check_dock(ticket.target_port)) + ticket.docking_error = "Targeted docking port invalid." return FALSE return TRUE diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 8c4a61e5dc25..f706bc87a491 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -211,6 +211,8 @@ var/json_key //Setting this to false will prevent the roundstart_template from being loaded on Initiallize(). You should set this to false if this loads a subship on a ship map template var/load_template_on_initialize = TRUE + /// The docking ticket of the ship docking to this port. + var/datum/docking_ticket/current_docking_ticket /obj/docking_port/stationary/Initialize(mapload) . = ..()