Skip to content

Commit

Permalink
Batch Mirroring (#1610)
Browse files Browse the repository at this point in the history
Batch Mirroring
  • Loading branch information
Iajret authored Jan 19, 2024
2 parents 3339c33 + d2d618c commit 7d9b697
Show file tree
Hide file tree
Showing 50 changed files with 539 additions and 374 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 @@ -714,13 +714,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 @@ -173,7 +173,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 @@ -189,10 +189,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 @@ -835,12 +837,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 @@ -645,7 +645,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 @@ -679,17 +679,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
1 change: 1 addition & 0 deletions code/datums/achievements/misc_achievements.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
name = "One Lean, Mean, Cleaning Machine"
desc = "How does it feel to know that your workplace values a mop bucket on wheels more than you?" // i can do better than this give me time
database_id = MEDAL_CLEANBOSS
icon = "cleanboss"

/datum/award/achievement/misc/rule8
name = "Rule 8"
Expand Down
120 changes: 60 additions & 60 deletions code/datums/station_traits/negative_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -381,69 +381,69 @@

/datum/station_trait/revolutionary_trashing/proc/trash_this_place()
for(var/area/station/command/area_to_trash in GLOB.areas)

for(var/turf/current_turf as anything in area_to_trash.get_contained_turfs())
if(isclosedturf(current_turf))
continue
if(prob(25))
var/obj/effect/decal/cleanable/crayon/created_art
created_art = new(current_turf, RANDOM_COLOUR, pick(trash_talk))
created_art.pixel_x = rand(-10, 10)
created_art.pixel_y = rand(-10, 10)

if(prob(0.01))
new /obj/effect/mob_spawn/corpse/human/assistant(current_turf)
continue

for(var/atom/current_thing as anything in current_turf.contents)
if(istype(current_thing, /obj/machinery/light) && prob(40))
var/obj/machinery/light/light_to_smash = current_thing
light_to_smash.break_light_tube(skip_sound_and_sparks = TRUE)
continue

if(istype(current_thing, /obj/structure/window))
if(prob(15))
current_thing.take_damage(rand(30, 90))
continue

if(istype(current_thing, /obj/structure/table) && prob(40))
current_thing.take_damage(100)
continue

if(istype(current_thing, /obj/structure/chair) && prob(60))
current_thing.take_damage(150)
continue

if(istype(current_thing, /obj/machinery/computer) && prob(30))
if(istype(current_thing, /obj/machinery/computer/communications))
continue //To prevent the shuttle from getting autocalled at the start of the round
current_thing.take_damage(160)
for (var/list/zlevel_turfs as anything in area_to_trash.get_zlevel_turf_lists())
for (var/turf/current_turf as anything in zlevel_turfs)
if(isclosedturf(current_turf))
continue

if(istype(current_thing, /obj/machinery/vending) && prob(45))
var/obj/machinery/vending/vendor_to_trash = current_thing
if(prob(50))
vendor_to_trash.tilt(get_turf(vendor_to_trash), 0) // crit effects can do some real weird shit, lets disable it

if(prob(50))
vendor_to_trash.take_damage(150)
continue

if(istype(current_thing, /obj/structure/fireaxecabinet)) //A staple of revolutionary behavior
current_thing.take_damage(90)
continue

if(istype(current_thing, /obj/item/bedsheet/captain))
new /obj/item/bedsheet/rev(current_thing.loc)
qdel(current_thing)
continue

if(istype(current_thing, /obj/item/bedsheet/captain/double))
new /obj/item/bedsheet/rev/double(current_thing.loc)
qdel(current_thing)
if(prob(25))
var/obj/effect/decal/cleanable/crayon/created_art
created_art = new(current_turf, RANDOM_COLOUR, pick(trash_talk))
created_art.pixel_x = rand(-10, 10)
created_art.pixel_y = rand(-10, 10)

if(prob(0.01))
new /obj/effect/mob_spawn/corpse/human/assistant(current_turf)
continue

CHECK_TICK
for(var/atom/current_thing as anything in current_turf.contents)
if(istype(current_thing, /obj/machinery/light) && prob(40))
var/obj/machinery/light/light_to_smash = current_thing
light_to_smash.break_light_tube(skip_sound_and_sparks = TRUE)
continue

if(istype(current_thing, /obj/structure/window))
if(prob(15))
current_thing.take_damage(rand(30, 90))
continue

if(istype(current_thing, /obj/structure/table) && prob(40))
current_thing.take_damage(100)
continue

if(istype(current_thing, /obj/structure/chair) && prob(60))
current_thing.take_damage(150)
continue

if(istype(current_thing, /obj/machinery/computer) && prob(30))
if(istype(current_thing, /obj/machinery/computer/communications))
continue //To prevent the shuttle from getting autocalled at the start of the round
current_thing.take_damage(160)
continue

if(istype(current_thing, /obj/machinery/vending) && prob(45))
var/obj/machinery/vending/vendor_to_trash = current_thing
if(prob(50))
vendor_to_trash.tilt(get_turf(vendor_to_trash), 0) // crit effects can do some real weird shit, lets disable it

if(prob(50))
vendor_to_trash.take_damage(150)
continue

if(istype(current_thing, /obj/structure/fireaxecabinet)) //A staple of revolutionary behavior
current_thing.take_damage(90)
continue

if(istype(current_thing, /obj/item/bedsheet/captain))
new /obj/item/bedsheet/rev(current_thing.loc)
qdel(current_thing)
continue

if(istype(current_thing, /obj/item/bedsheet/captain/double))
new /obj/item/bedsheet/rev/double(current_thing.loc)
qdel(current_thing)
continue

CHECK_TICK

///Station traits that influence the space background and apply some unique effects!
/datum/station_trait/nebula
Expand Down
Loading

0 comments on commit 7d9b697

Please sign in to comment.