From 678a7c4da24e6bd965d8aab762c1921af4c4cf2b Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 30 Mar 2025 10:24:59 -0500 Subject: [PATCH] Refactor basketball minigame to use lazyloading (#90149) Basketball minigame is now lazyloaded. Several notable changes include: - Basketball spawns in lazyload z-levels instead of Centcomm. The basketball landmark has been removed from Centcomm map. - `soviet_bear.dmm` basketball map was incorrectly referenced as `soviet_bears` in the old maploader code causing it to break when it tried to load this map - All `Basketball` maps were moved to a new map folder called `minigames` which I plan on placing all minigame maps inside - Basketball mobs would runtime when qdel since they have still have clients inside them. The solution was to ghostize the mobs before this happens. This does not directly fix the lag or runtimes being caused by basketball. That is caused by the maploader code inserting walls into the atmos subsystem due to some really weird behavior that I explained in #89649 . I have a seperate fix I'm planning for that. --- _maps/map_files/generic/CentCom.dmm | 6 +- .../basketball}/ash_gladiators.dmm | 0 .../basketball}/ass_blast_usa.dmm | 0 .../basketball}/beach_bums.dmm | 0 .../basketball}/greytide_worldwide.dmm | 0 .../basketball}/lusty_xenomorphs.dmm | 0 .../basketball}/soviet_bear.dmm | 0 .../basketball}/space_surfers.dmm | 0 .../basketball}/stadium.dmm | 0 code/__HELPERS/lazy_templates.dm | 2 + .../basketball/basketball_map_loading.dm | 52 ++++++----- code/modules/basketball/controller.dm | 93 +++++++++---------- 12 files changed, 80 insertions(+), 73 deletions(-) rename _maps/{map_files/Basketball => minigame/basketball}/ash_gladiators.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/ass_blast_usa.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/beach_bums.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/greytide_worldwide.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/lusty_xenomorphs.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/soviet_bear.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/space_surfers.dmm (100%) rename _maps/{map_files/Basketball => minigame/basketball}/stadium.dmm (100%) diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index b17485bfd3c..5011ff60733 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -6911,10 +6911,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/centcom/central_command_areas/ferry) -"Fi" = ( -/obj/effect/landmark/basketball/game_area, -/turf/open/space/basic, -/area/space) "Fj" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/centcom{ @@ -36282,7 +36278,7 @@ aa aa aa aa -Fi +aa aa aa aa diff --git a/_maps/map_files/Basketball/ash_gladiators.dmm b/_maps/minigame/basketball/ash_gladiators.dmm similarity index 100% rename from _maps/map_files/Basketball/ash_gladiators.dmm rename to _maps/minigame/basketball/ash_gladiators.dmm diff --git a/_maps/map_files/Basketball/ass_blast_usa.dmm b/_maps/minigame/basketball/ass_blast_usa.dmm similarity index 100% rename from _maps/map_files/Basketball/ass_blast_usa.dmm rename to _maps/minigame/basketball/ass_blast_usa.dmm diff --git a/_maps/map_files/Basketball/beach_bums.dmm b/_maps/minigame/basketball/beach_bums.dmm similarity index 100% rename from _maps/map_files/Basketball/beach_bums.dmm rename to _maps/minigame/basketball/beach_bums.dmm diff --git a/_maps/map_files/Basketball/greytide_worldwide.dmm b/_maps/minigame/basketball/greytide_worldwide.dmm similarity index 100% rename from _maps/map_files/Basketball/greytide_worldwide.dmm rename to _maps/minigame/basketball/greytide_worldwide.dmm diff --git a/_maps/map_files/Basketball/lusty_xenomorphs.dmm b/_maps/minigame/basketball/lusty_xenomorphs.dmm similarity index 100% rename from _maps/map_files/Basketball/lusty_xenomorphs.dmm rename to _maps/minigame/basketball/lusty_xenomorphs.dmm diff --git a/_maps/map_files/Basketball/soviet_bear.dmm b/_maps/minigame/basketball/soviet_bear.dmm similarity index 100% rename from _maps/map_files/Basketball/soviet_bear.dmm rename to _maps/minigame/basketball/soviet_bear.dmm diff --git a/_maps/map_files/Basketball/space_surfers.dmm b/_maps/minigame/basketball/space_surfers.dmm similarity index 100% rename from _maps/map_files/Basketball/space_surfers.dmm rename to _maps/minigame/basketball/space_surfers.dmm diff --git a/_maps/map_files/Basketball/stadium.dmm b/_maps/minigame/basketball/stadium.dmm similarity index 100% rename from _maps/map_files/Basketball/stadium.dmm rename to _maps/minigame/basketball/stadium.dmm diff --git a/code/__HELPERS/lazy_templates.dm b/code/__HELPERS/lazy_templates.dm index 10b9b6dac16..87f51d9d129 100644 --- a/code/__HELPERS/lazy_templates.dm +++ b/code/__HELPERS/lazy_templates.dm @@ -9,6 +9,8 @@ GLOBAL_LIST_INIT(lazy_templates, generate_lazy_template_map()) . = list() for(var/datum/lazy_template/template as anything in subtypesof(/datum/lazy_template)) var/key = initial(template.key) + if(!key) // some subtypes like basketball and deathmatch have a base datum with no key + continue if(key in .) stack_trace("Found multiple lazy templates with the same key! '[key]'") .[key] = new template diff --git a/code/modules/basketball/basketball_map_loading.dm b/code/modules/basketball/basketball_map_loading.dm index 5ed18997dde..1dac2043668 100644 --- a/code/modules/basketball/basketball_map_loading.dm +++ b/code/modules/basketball/basketball_map_loading.dm @@ -1,9 +1,6 @@ /obj/effect/landmark/basketball name = "Basketball Map Spawner" -/obj/effect/landmark/basketball/game_area - name = "Basketball Game Location" - /obj/effect/landmark/basketball/team_spawn name = "Basketball Team Spawner" var/game_id = "basketball" @@ -35,66 +32,79 @@ flags_1 = NONE area_flags = UNIQUE_AREA | NOTELEPORT | NO_DEATH_MESSAGE | BLOCK_SUICIDE -/datum/map_template/basketball - should_place_on_top = FALSE +/datum/lazy_template/basketball + map_dir = "_maps/minigame/basketball" + place_on_top = TRUE + turf_reservation_type = /datum/turf_reservation/turf_not_baseturf + /// Map UI Name + var/name + /// Map Description var/description = "" /// The name of the basketball team var/team_name /// The basketball teams home stadium uniform var/home_team_uniform -/datum/map_template/basketball/stadium +/datum/lazy_template/basketball/stadium name = "Stadium" description = "The homecourt for the Nanotrasen Basketball Department." - mappath = "_maps/map_files/basketball/stadium.dmm" + map_name = "stadium" + key = "stadium" team_name = "Nanotrasen Basketball Department" home_team_uniform = /datum/outfit/basketball/nanotrasen -/datum/map_template/basketball/lusty_xenomorphs +/datum/lazy_template/basketball/lusty_xenomorphs name = "Lusty Xenomorphs Stadium" description = "The homecourt of the Lusty Xenomorphs." - mappath = "_maps/map_files/basketball/lusty_xenomorphs.dmm" + map_name = "lusty_xenomorphs" + key = "lusty_xenomorphs" team_name = "Lusty Xenomorphs" home_team_uniform = /datum/outfit/basketball/lusty_xenomorphs -/datum/map_template/basketball/space_surfers +/datum/lazy_template/basketball/space_surfers name = "Space Surfers Stadium" description = "The homecourt of the Space Surfers." - mappath = "_maps/map_files/basketball/space_surfers.dmm" + map_name = "space_surfers" + key = "space_surfers" team_name = "Space Surfers" home_team_uniform = /datum/outfit/basketball/space_surfers -/datum/map_template/basketball/greytide_worldwide +/datum/lazy_template/basketball/greytide_worldwide name = "Greytide Worldwide Stadium" description = "The homecourt of the Greytide Worldwide." - mappath = "_maps/map_files/basketball/greytide_worldwide.dmm" + map_name = "greytide_worldwide" + key = "greytide_worldwide" team_name = "Greytide Worldwide" home_team_uniform = /datum/outfit/basketball/greytide_worldwide -/datum/map_template/basketball/ass_blast_usa +/datum/lazy_template/basketball/ass_blast_usa name = "Ass Blast USA Stadium" description = "The homecourt of the Ass Blast USA." - mappath = "_maps/map_files/basketball/ass_blast_usa.dmm" + map_name = "ass_blast_usa" + key = "ass_blast_usa" team_name = "Ass Blast USA" home_team_uniform = /datum/outfit/basketball/ass_blast_usa -/datum/map_template/basketball/soviet_bears +/datum/lazy_template/basketball/soviet_bears name = "Soviet Bears Stadium" description = "The homecourt of the Soviet Bears." - mappath = "_maps/map_files/basketball/soviet_bears.dmm" + map_name = "soviet_bear" + key = "soviet_bear" team_name = "Soviet Bears" home_team_uniform = /datum/outfit/basketball/soviet_bears -/datum/map_template/basketball/ash_gladiators +/datum/lazy_template/basketball/ash_gladiators name = "Ash Gladiators Stadium" description = "The homecourt of the Ash Gladiators." - mappath = "_maps/map_files/basketball/ash_gladiators.dmm" + map_name = "ash_gladiators" + key = "ash_gladiators" team_name = "Ash Gladiators" home_team_uniform = /datum/outfit/basketball/ash_gladiators -/datum/map_template/basketball/beach_bums +/datum/lazy_template/basketball/beach_bums name = "Beach Bums Stadium" description = "The homecourt of the Beach Bums." - mappath = "_maps/map_files/basketball/beach_bums.dmm" + map_name = "beach_bums" + key = "beach_bums" team_name = "Beach Bums" home_team_uniform = /datum/outfit/basketball/beach_bums diff --git a/code/modules/basketball/controller.dm b/code/modules/basketball/controller.dm index d7f58f11903..de32aa766bb 100644 --- a/code/modules/basketball/controller.dm +++ b/code/modules/basketball/controller.dm @@ -18,26 +18,29 @@ GLOBAL_VAR(basketball_game) */ /datum/basketball_controller /// Template picked when the game starts. used for the name and desc reading - var/datum/map_template/basketball/current_map - /// Map generation tool that deletes the current map after the game finishes - var/datum/map_generator/massdelete/map_deleter + var/datum/lazy_template/basketball/current_map + /// Our turf reservation AKA where the arena is + var/datum/turf_reservation/location /// Total amount of time basketball is played for var/game_duration = 3 MINUTES /// List of all players ckeys involved in the minigame - var/list/minigame_players = list() + var/list/minigame_players_ckeys = list() + /// List of all player mobs involved in the minigame + var/list/minigame_basketball_mobs = list() /// Spawn points for home team players var/list/home_team_landmarks = list() /// List of home team players ckeys - var/list/home_team_players = list() + var/list/home_team_ckeys = list() + /// The basketball hoop used by home team var/obj/structure/hoop/minigame/home_hoop /// Spawn points for away team players var/list/away_team_landmarks = list() /// List of away team players ckeys - var/list/away_team_players = list() + var/list/away_team_ckeys = list() /// The basketball hoop used by away team var/obj/structure/hoop/minigame/away_hoop @@ -46,14 +49,17 @@ GLOBAL_VAR(basketball_game) /datum/basketball_controller/New() . = ..() + if(GLOB.basketball_game) + qdel(src) + CRASH("A basketball controller already exists.") GLOB.basketball_game = src - map_deleter = new /datum/basketball_controller/Destroy(force) . = ..() GLOB.basketball_game = null + current_map = null + location = null end_game() - qdel(map_deleter) /** * Triggers at beginning of the game when there is a confirmed list of valid, ready players. @@ -68,18 +74,13 @@ GLOBAL_VAR(basketball_game) * * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles */ /datum/basketball_controller/proc/prepare_game(ready_players) - var/list/possible_maps = subtypesof(/datum/map_template/basketball) - var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/basketball/game_area) in GLOB.landmarks_list) + var/list/possible_maps = subtypesof(/datum/lazy_template/basketball) current_map = pick(possible_maps) current_map = new current_map - - if(!spawn_area) - CRASH("No spawn area detected for Basketball Minigame!") - var/list/bounds = current_map.load(spawn_area) - if(!bounds) + location = current_map.lazy_load() + if(!location) CRASH("Loading basketball map failed!") - map_deleter.defineRegion(spawn_area, locate(spawn_area.x + 23, spawn_area.y + 25, spawn_area.z), replace = TRUE) //so we're ready to mass delete when round ends var/turf/home_hoop_turf = get_turf(locate(/obj/effect/landmark/basketball/team_spawn/home_hoop) in GLOB.landmarks_list) if(!home_hoop_turf) @@ -134,9 +135,8 @@ GLOBAL_VAR(basketball_game) * Called when the game is setting up, AFTER map is loaded but BEFORE the game start. Creates and places each body and gives the correct player key */ /datum/basketball_controller/proc/create_bodies(ready_players) - var/list/possible_away_teams = subtypesof(/datum/map_template/basketball) - current_map.type - var/datum/map_template/basketball/away_map = pick(possible_away_teams) - away_map = new away_map + var/list/possible_away_teams = subtypesof(/datum/lazy_template/basketball) - current_map.type + var/datum/lazy_template/basketball/away_map = pick(possible_away_teams) var/list/home_spawnpoints = home_team_landmarks.Copy() var/list/away_spawnpoints = away_team_landmarks.Copy() @@ -148,7 +148,7 @@ GLOBAL_VAR(basketball_game) // rename the hoops to their appropriate teams names home_hoop.name = current_map.team_name - away_hoop.name = away_map.team_name + away_hoop.name = away_map::team_name var/player_count = 0 // if total players is odd number then the odd man out is a referee @@ -156,7 +156,7 @@ GLOBAL_VAR(basketball_game) for(var/player_key in ready_players) player_count++ - minigame_players |= player_key + minigame_players_ckeys |= player_key var/is_player_referee = (player_count == length(ready_players) && minigame_has_referee) @@ -165,16 +165,16 @@ GLOBAL_VAR(basketball_game) team_uniform = /datum/outfit/basketball/referee else if(player_count % 2) // odd is home team spawn_landmark = pick_n_take(home_spawnpoints) - home_team_players |= player_key + home_team_ckeys |= player_key away_hoop.team_ckeys |= player_key // to restrict scoring on opponents hoop rapidly team_uniform = current_map.home_team_uniform team_name = current_map.team_name else // even is away team spawn_landmark = pick_n_take(away_spawnpoints) - away_team_players |= player_key + away_team_ckeys |= player_key home_hoop.team_ckeys |= player_key // to restrict scoring on opponents hoop rapidly - team_uniform = away_map.home_team_uniform - team_name = away_map.team_name + team_uniform = away_map::home_team_uniform + team_name = away_map::team_name var/mob/living/carbon/human/baller = new(get_turf(spawn_landmark)) @@ -199,6 +199,7 @@ GLOBAL_VAR(basketball_game) old_body = player_client.mob.mind.current, \ ) baller.PossessByPlayer(player_key) + minigame_basketball_mobs |= baller SEND_SOUND(baller, sound('sound/items/whistle/whistle.ogg', volume=30)) if(is_player_referee) @@ -221,34 +222,31 @@ GLOBAL_VAR(basketball_game) if(home_hoop.total_score == away_hoop.total_score) is_game_draw = TRUE - winner_team_ckeys |= home_team_players - winner_team_ckeys |= away_team_players + winner_team_ckeys |= home_team_ckeys + winner_team_ckeys |= away_team_ckeys else if(home_hoop.total_score > away_hoop.total_score) - winner_team_ckeys = away_team_players + winner_team_ckeys = away_team_ckeys winner_team_name = away_hoop.name - loser_team_ckeys = home_team_players + loser_team_ckeys = home_team_ckeys else if(home_hoop.total_score < away_hoop.total_score) - winner_team_ckeys = home_team_players + winner_team_ckeys = home_team_ckeys winner_team_name = home_hoop.name - loser_team_ckeys = away_team_players + loser_team_ckeys = away_team_ckeys if(is_game_draw) for(var/ckey in winner_team_ckeys) var/mob/living/competitor = get_mob_by_ckey(ckey) - var/area/mob_area = get_area(competitor) - if(istype(competitor) && istype(mob_area, /area/centcom/basketball)) + if(competitor in minigame_basketball_mobs) to_chat(competitor, span_hypnophrase("The game resulted in a draw!")) else for(var/ckey in winner_team_ckeys) var/mob/living/competitor = get_mob_by_ckey(ckey) - var/area/mob_area = get_area(competitor) - if(istype(competitor) && istype(mob_area, /area/centcom/basketball)) + if(competitor in minigame_basketball_mobs) to_chat(competitor, span_hypnophrase("[winner_team_name] team wins!")) for(var/ckey in loser_team_ckeys) var/mob/living/competitor = get_mob_by_ckey(ckey) - var/area/mob_area = get_area(competitor) - if(istype(competitor) && istype(mob_area, /area/centcom/basketball)) + if(competitor in minigame_basketball_mobs) to_chat(competitor, span_hypnophrase("[winner_team_name] team wins!")) competitor.dust() @@ -258,19 +256,20 @@ GLOBAL_VAR(basketball_game) * Cleans up the game, resetting variables back to the beginning and removing the map with the generator. */ /datum/basketball_controller/proc/end_game() - for(var/ckey in minigame_players) - var/mob/living/competitor = get_mob_by_ckey(ckey) - var/area/mob_area = get_area(competitor) - if(istype(competitor) && istype(mob_area, /area/centcom/basketball)) - QDEL_NULL(competitor) - - map_deleter.generate() //remove the map, it will be loaded at the start of the next one - QDEL_NULL(current_map) - - //map gen does not deal with landmarks + for(var/mob/living/living in minigame_basketball_mobs) + living.ghostize(can_reenter_corpse = FALSE) // avoids runtimes when a cliented mob is qdel'd + QDEL_LIST(minigame_basketball_mobs) QDEL_LIST(home_team_landmarks) QDEL_LIST(away_team_landmarks) QDEL_LIST(referee_landmark) + for(var/obj/effect/landmark/basketball/team_spawn/hoop in GLOB.landmarks_list) + qdel(hoop) + + for(var/turf/victimized_turf as anything in location.reserved_turfs) //remove this once clearing turf reservations is actually reliable + victimized_turf.empty() + current_map.reservations -= location + current_map = null + QDEL_NULL(location) /** * Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.