Skip to content

Commit

Permalink
Merge pull request #2310 from Bird-Lounge/upstream-merge-80941
Browse files Browse the repository at this point in the history
[MIRROR] split area.contained_turfs up by zlevel, make init 10 seconds faster
  • Loading branch information
CliffracerX authored Jan 19, 2024
2 parents 33c74e4 + 7e9aaa6 commit e48d14a
Show file tree
Hide file tree
Showing 42 changed files with 612 additions and 323 deletions.
13 changes: 13 additions & 0 deletions code/__HELPERS/_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@
LAZYINITLIST(lazy_list[key]); \
lazy_list[key] |= value;

///Ensures the length of a list is at least I, prefilling it with V if needed. if V is a proc call, it is repeated for each new index so that list() can just make a new list for each item.
#define LISTASSERTLEN(L, I, V...) \
if (length(L) < I) { \
var/_OLD_LENGTH = length(L); \
L.len = I; \
/* Convert the optional argument to a if check */ \
for (var/_USELESS_VAR in list(V)) { \
for (var/_INDEX_TO_ASSIGN_TO in _OLD_LENGTH+1 to I) { \
L[_INDEX_TO_ASSIGN_TO] = V; \
} \
} \
}

#define reverseList(L) reverse_range(L.Copy())

/// Passed into BINARY_INSERT to compare keys
Expand Down
10 changes: 4 additions & 6 deletions code/__HELPERS/areas.dm
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,11 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
// Now their turfs
var/list/turfs = list()
for(var/area/pull_from as anything in areas_to_pull)
var/list/our_turfs = pull_from.get_contained_turfs()
if(target_z == 0)
turfs += our_turfs
if (target_z == 0)
for (var/list/zlevel_turfs as anything in pull_from.get_zlevel_turf_lists())
turfs += zlevel_turfs
else
for(var/turf/turf_in_area as anything in our_turfs)
if(target_z == turf_in_area.z)
turfs += turf_in_area
turfs += pull_from.get_turfs_by_zlevel(target_z)
return turfs


Expand Down
49 changes: 31 additions & 18 deletions code/controllers/subsystem/area_contents.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define ALLOWED_LOOSE_TURFS 500
#define ALLOWED_LOOSE_TURFS 100
/**
* Responsible for managing the sizes of area.contained_turfs and area.turfs_to_uncontain
* These lists do not check for duplicates, which is fine, but it also means they can balloon in size over time
Expand All @@ -17,8 +17,11 @@ SUBSYSTEM_DEF(area_contents)
var/total_clearing_from = 0
var/total_to_clear = 0
for(var/area/to_clear as anything in marked_for_clearing)
total_to_clear += length(to_clear.turfs_to_uncontain)
total_clearing_from += length(to_clear.contained_turfs)
for (var/area_zlevel in 1 to length(to_clear.turfs_to_uncontain_by_zlevel))
if (length(to_clear.turfs_to_uncontain_by_zlevel[area_zlevel]))
total_to_clear += length(to_clear.turfs_to_uncontain_by_zlevel[area_zlevel])
if (length(to_clear.turfs_by_zlevel) >= area_zlevel) //this should always be true, but stat_entry is no place for runtimes. fire() can handle that
total_clearing_from += length(to_clear.turfs_by_zlevel[area_zlevel])
msg = "A:[length(currentrun)] MR:[length(marked_for_clearing)] TC:[total_to_clear] CF:[total_clearing_from]"
return ..()

Expand All @@ -29,8 +32,10 @@ SUBSYSTEM_DEF(area_contents)

while(length(currentrun))
var/area/test = currentrun[length(currentrun)]
if(length(test.turfs_to_uncontain) > ALLOWED_LOOSE_TURFS)
marked_for_clearing |= test
for (var/area_zlevel in 1 to length(test.turfs_to_uncontain_by_zlevel))
if(length(test.turfs_to_uncontain_by_zlevel[area_zlevel]) > ALLOWED_LOOSE_TURFS)
marked_for_clearing |= test
break
currentrun.len--
if(MC_TICK_CHECK)
return
Expand All @@ -39,19 +44,27 @@ SUBSYSTEM_DEF(area_contents)
while(length(marked_for_clearing))
var/area/clear = marked_for_clearing[length(marked_for_clearing)]

// The operation of cutting large lists can be expensive
// It scales almost directly with the size of the list we're cutting with
// Because of this, we're gonna stick to cutting 1 entry at a time
// There's no reason to batch it I promise, this is faster. No overtime too
var/amount_cut = 0
var/list/cut_from = clear.turfs_to_uncontain
for(amount_cut in 1 to length(cut_from))
clear.contained_turfs -= cut_from[amount_cut]
if(MC_TICK_CHECK)
cut_from.Cut(1, amount_cut + 1)
return

clear.turfs_to_uncontain = list()
for (var/area_zlevel in 1 to length(clear.turfs_to_uncontain_by_zlevel))
if (!length(clear.turfs_to_uncontain_by_zlevel[area_zlevel]))
continue
if (length(clear.turfs_by_zlevel) < area_zlevel)
stack_trace("[clear]([clear.type])'s turfs_by_zlevel is length [length(clear.turfs_by_zlevel)] but we are being asked to remove turfs from zlevel [area_zlevel] from it.")
clear.turfs_to_uncontain_by_zlevel[area_zlevel] = list()
continue

// The operation of cutting large lists can be expensive
// It scales almost directly with the size of the list we're cutting with
// Because of this, we're gonna stick to cutting 1 entry at a time
// There's no reason to batch it I promise, this is faster. No overtime too
var/amount_cut = 0
var/list/cut_from = clear.turfs_to_uncontain_by_zlevel[area_zlevel]
for(amount_cut in 1 to length(cut_from))
clear.turfs_by_zlevel[area_zlevel] -= cut_from[amount_cut]
if(MC_TICK_CHECK)
cut_from.Cut(1, amount_cut + 1)
return

clear.turfs_to_uncontain_by_zlevel = list()
marked_for_clearing.len--

#undef ALLOWED_LOOSE_TURFS
15 changes: 8 additions & 7 deletions code/controllers/subsystem/job.dm
Original file line number Diff line number Diff line change
Expand Up @@ -712,13 +712,14 @@ SUBSYSTEM_DEF(job)
var/area/shuttle/arrival/arrivals_area = GLOB.areas_by_type[/area/shuttle/arrival]
if(!isnull(arrivals_area))
var/list/turf/available_turfs = list()
for(var/turf/arrivals_turf as anything in arrivals_area.get_contained_turfs())
var/obj/structure/chair/shuttle_chair = locate() in arrivals_turf
if(!isnull(shuttle_chair))
return shuttle_chair
if(arrivals_turf.is_blocked_turf(TRUE))
continue
available_turfs += arrivals_turf
for (var/list/zlevel_turfs as anything in arrivals_area.get_zlevel_turf_lists())
for (var/turf/arrivals_turf as anything in zlevel_turfs)
var/obj/structure/chair/shuttle_chair = locate() in arrivals_turf
if(!isnull(shuttle_chair))
return shuttle_chair
if(arrivals_turf.is_blocked_turf(TRUE))
continue
available_turfs += arrivals_turf

if(length(available_turfs))
return pick(available_turfs)
Expand Down
14 changes: 9 additions & 5 deletions code/controllers/subsystem/mapping.dm
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ SUBSYSTEM_DEF(mapping)
// Cache for sonic speed
var/list/unused_turfs = src.unused_turfs
var/list/world_contents = GLOB.areas_by_type[world.area].contents
var/list/world_turf_contents = GLOB.areas_by_type[world.area].contained_turfs
var/list/world_turf_contents_by_z = GLOB.areas_by_type[world.area].turfs_by_zlevel
var/list/lists_to_reserve = src.lists_to_reserve
var/index = 0
while(index < length(lists_to_reserve))
Expand All @@ -192,10 +192,12 @@ SUBSYSTEM_DEF(mapping)
LAZYINITLIST(unused_turfs["[T.z]"])
unused_turfs["[T.z]"] |= T
var/area/old_area = T.loc
old_area.turfs_to_uncontain += T
LISTASSERTLEN(old_area.turfs_to_uncontain_by_zlevel, T.z, list())
old_area.turfs_to_uncontain_by_zlevel[T.z] += T
T.turf_flags = UNUSED_RESERVATION_TURF
world_contents += T
world_turf_contents += T
LISTASSERTLEN(world_turf_contents_by_z, T.z, list())
world_turf_contents_by_z[T.z] += T
packet.len--
packetlen = length(packet)

Expand Down Expand Up @@ -869,12 +871,14 @@ GLOBAL_LIST_EMPTY(the_station_areas)
// Faster
if(space_guaranteed)
var/area/global_area = GLOB.areas_by_type[world.area]
global_area.contained_turfs += Z_TURFS(z_level)
LISTASSERTLEN(global_area.turfs_by_zlevel, z_level, list())
global_area.turfs_by_zlevel[z_level] = Z_TURFS(z_level)
return

for(var/turf/to_contain as anything in Z_TURFS(z_level))
var/area/our_area = to_contain.loc
our_area.contained_turfs += to_contain
LISTASSERTLEN(our_area.turfs_by_zlevel, z_level, list())
our_area.turfs_by_zlevel[z_level] += to_contain

/datum/controller/subsystem/mapping/proc/update_plane_tracking(datum/space_level/update_with)
// We're essentially going to walk down the stack of connected z levels, and set their plane offset as we go
Expand Down
7 changes: 4 additions & 3 deletions code/controllers/subsystem/radioactive_nebula.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ SUBSYSTEM_DEF(radioactive_nebula)
/// Loop through radioactive space (with lag checks) and make it all radioactive!
/datum/controller/subsystem/radioactive_nebula/proc/irradiate_everything()
for (var/area/area as anything in get_areas(radioactive_nebula.radioactive_areas))
for (var/turf/turf as anything in area.get_contained_turfs())
for (var/atom/movable/target as anything in turf)
fake_irradiate(target)
for (var/list/zlevel_turfs as anything in area.get_zlevel_turf_lists())
for (var/turf/area_turf as anything in zlevel_turfs)
for (var/atom/movable/target as anything in area_turf)
fake_irradiate(target)

CHECK_TICK

Expand Down
19 changes: 12 additions & 7 deletions code/controllers/subsystem/shuttle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ SUBSYSTEM_DEF(shuttle)
var/datum/turf_reservation/proposal = SSmapping.request_turf_block_reservation(
transit_width,
transit_height,
1,
z_size = 1, //if this is changed the turf uncontain code below has to be updated to support multiple zs
reservation_type = /datum/turf_reservation/transit,
turf_type_override = transit_path,
)
Expand Down Expand Up @@ -663,17 +663,22 @@ SUBSYSTEM_DEF(shuttle)
if(!midpoint)
qdel(proposal)
return FALSE

var/area/old_area = midpoint.loc
old_area.turfs_to_uncontain += proposal.reserved_turfs
var/area/shuttle/transit/A = new()
A.parallax_movedir = travel_dir
A.contents = proposal.reserved_turfs
A.contained_turfs = proposal.reserved_turfs
LISTASSERTLEN(old_area.turfs_to_uncontain_by_zlevel, bottomleft.z, list())
old_area.turfs_to_uncontain_by_zlevel[bottomleft.z] += proposal.reserved_turfs

var/area/shuttle/transit/new_area = new()
new_area.parallax_movedir = travel_dir
new_area.contents = proposal.reserved_turfs
LISTASSERTLEN(new_area.turfs_by_zlevel, bottomleft.z, list())
new_area.turfs_by_zlevel[bottomleft.z] = proposal.reserved_turfs

var/obj/docking_port/stationary/transit/new_transit_dock = new(midpoint)
new_transit_dock.reserved_area = proposal
new_transit_dock.name = "Transit for [M.shuttle_id]/[M.name]"
new_transit_dock.owner = M
new_transit_dock.assigned_area = A
new_transit_dock.assigned_area = new_area

// Add 180, because ports point inwards, rather than outwards
new_transit_dock.setDir(angle2dir(dock_angle))
Expand Down
61 changes: 61 additions & 0 deletions code/datums/station_traits/job_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,64 @@
// monkey carries the crates, the age of robot is over
if(GLOB.cargo_ripley)
qdel(GLOB.cargo_ripley)
<<<<<<< HEAD
=======

/datum/station_trait/job/bridge_assistant
name = "Bridge Assistant"
button_desc = "Sign up to become the Bridge Assistant and watch over the Bridge."
weight = 2
report_message = "We have installed a Bridge Assistant on your station."
show_in_report = TRUE
can_roll_antag = CAN_ROLL_PROTECTED
job_to_add = /datum/job/bridge_assistant

/datum/station_trait/job/bridge_assistant/New()
. = ..()
RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(add_coffeemaker))

/datum/station_trait/job/bridge_assistant/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays)
. = ..()
overlays += "bridge_assistant"

/// Creates a coffeemaker in the bridge, if we don't have one yet.
/datum/station_trait/job/bridge_assistant/proc/add_coffeemaker(datum/source)
SIGNAL_HANDLER
var/area/bridge = GLOB.areas_by_type[/area/station/command/bridge]
if(isnull(bridge)) //no bridge, what will he assist?
return
var/list/possible_coffeemaker_positions = list(/area/station/command/bridge, /area/station/command/meeting_room)
var/list/coffeemakers = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/coffeemaker)
for(var/obj/machinery/coffeemaker as anything in coffeemakers) //don't spawn a coffeemaker if there is already one on the bridge
if(is_type_in_list(get_area(coffeemaker), possible_coffeemaker_positions))
return
var/list/tables = list()
for(var/turf/area_turf as anything in bridge.get_turfs_from_all_zlevels())
var/obj/structure/table/table = locate() in area_turf
if(isnull(table))
continue
if(area_turf.is_blocked_turf(ignore_atoms = list(table))) //don't spawn a coffeemaker on a fax machine or smth
continue
tables += table
if(!length(tables))
return
var/picked_table = pick_n_take(tables)
var/picked_turf = get_turf(picked_table)
if(length(tables))
var/another_table = pick(tables)
for(var/obj/thing_on_table in picked_turf) //if there's paper bins or other shit on the table, get that off
if(thing_on_table == picked_table)
continue
if(HAS_TRAIT(thing_on_table, TRAIT_WALLMOUNTED) || (thing_on_table.flags_1 & ON_BORDER_1) || thing_on_table.layer < TABLE_LAYER)
continue
if(thing_on_table.invisibility || !thing_on_table.alpha || !thing_on_table.mouse_opacity)
continue
thing_on_table.forceMove(get_turf(another_table))
new /obj/machinery/coffeemaker/impressa(picked_turf)
new /obj/item/reagent_containers/cup/coffeepot(picked_turf)
new /obj/item/storage/box/coffeepack(picked_turf)

#undef CAN_ROLL_ALWAYS
#undef CAN_ROLL_PROTECTED
#undef CAN_ROLL_NEVER
>>>>>>> 8703eac50de (split area.contained_turfs up by zlevel, make init 10 seconds faster (#80941))
Loading

0 comments on commit e48d14a

Please sign in to comment.