[MIRROR] Space/Changeturf fixes and optimizations [MDB IGNORE] (#19201)

Space/Changeturf fixes and optimizations

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-02-28 21:23:35 +01:00
committed by GitHub
parent f558095a40
commit db33d75a5e
20 changed files with 231 additions and 120 deletions

View File

@@ -15,7 +15,7 @@
#define INIT_COST(costs, counting) \ #define INIT_COST(costs, counting) \
var/list/_costs = costs; \ var/list/_costs = costs; \
var/list/_counting = counting; \ var/list/_counting = counting; \
var/usage = TICK_USAGE; var/_usage = TICK_USAGE;
// STATIC cost tracking macro. Uses static lists instead of the normal global ones // STATIC cost tracking macro. Uses static lists instead of the normal global ones
// Good for debug stuff, and for running before globals init // Good for debug stuff, and for running before globals init
@@ -31,16 +31,16 @@
costs = hidden_static_list_for_fun1; \ costs = hidden_static_list_for_fun1; \
counting = hidden_static_list_for_fun2 ; \ counting = hidden_static_list_for_fun2 ; \
} \ } \
usage = TICK_USAGE; _usage = TICK_USAGE;
#define SET_COST(category) \ #define SET_COST(category) \
do { \ do { \
var/cost = TICK_USAGE; \ var/_cost = TICK_USAGE; \
_costs[category] += TICK_DELTA_TO_MS(cost - usage);\ _costs[category] += TICK_DELTA_TO_MS(_cost - _usage);\
_counting[category] += 1; \ _counting[category] += 1; \
} while(FALSE); \ } while(FALSE); \
usage = TICK_USAGE; _usage = TICK_USAGE;
#define SET_COST_LINE(...) SET_COST("[__LINE__]") #define SET_COST_LINE(...) SET_COST("[__LINE__]")
@@ -62,4 +62,5 @@
##proc(filename, costs, counts); \ ##proc(filename, costs, counts); \
} \ } \
} \ } \
} while (FALSE); } while (FALSE); \
_usage = TICK_USAGE;

View File

@@ -348,19 +348,27 @@
///Returns the open turf next to the center in a specific direction ///Returns the open turf next to the center in a specific direction
/proc/get_open_turf_in_dir(atom/center, dir) /proc/get_open_turf_in_dir(atom/center, dir)
var/turf/open/get_turf = get_ranged_target_turf(center, dir, 1) var/turf/open/get_turf = get_step(center, dir)
if(istype(get_turf)) if(istype(get_turf))
return get_turf return get_turf
///Returns a list with all the adjacent open turfs. Clears the list of nulls in the end. ///Returns a list with all the adjacent open turfs. Clears the list of nulls in the end.
/proc/get_adjacent_open_turfs(atom/center) /proc/get_adjacent_open_turfs(atom/center)
. = list( var/list/hand_back = list()
get_open_turf_in_dir(center, NORTH), // Inlined get_open_turf_in_dir, just to be fast
get_open_turf_in_dir(center, SOUTH), var/turf/open/new_turf = get_step(center, NORTH)
get_open_turf_in_dir(center, EAST), if(istype(new_turf))
get_open_turf_in_dir(center, WEST) hand_back += new_turf
) new_turf = get_step(center, SOUTH)
list_clear_nulls(.) if(istype(new_turf))
hand_back += new_turf
new_turf = get_step(center, EAST)
if(istype(new_turf))
hand_back += new_turf
new_turf = get_step(center, WEST)
if(istype(new_turf))
hand_back += new_turf
return hand_back
///Returns a list with all the adjacent areas by getting the adjacent open turfs ///Returns a list with all the adjacent areas by getting the adjacent open turfs
/proc/get_adjacent_open_areas(atom/center) /proc/get_adjacent_open_areas(atom/center)

View File

@@ -148,13 +148,13 @@ SUBSYSTEM_DEF(mapping)
#endif #endif
// Run map generation after ruin generation to prevent issues // Run map generation after ruin generation to prevent issues
run_map_generation() run_map_generation()
// Add the transit level // Add the first transit level
transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE)) var/datum/space_level/base_transit = add_reservation_zlevel()
require_area_resort() require_area_resort()
// Set up Z-level transitions. // Set up Z-level transitions.
setup_map_transitions() setup_map_transitions()
generate_station_area_list() generate_station_area_list()
initialize_reserved_level(transit.z_value) initialize_reserved_level(base_transit.z_value)
calculate_default_z_level_gravities() calculate_default_z_level_gravities()
return SS_INIT_SUCCESS return SS_INIT_SUCCESS
@@ -171,7 +171,8 @@ SUBSYSTEM_DEF(mapping)
var/packetlen = length(packet) var/packetlen = length(packet)
while(packetlen) while(packetlen)
if(MC_TICK_CHECK) if(MC_TICK_CHECK)
lists_to_reserve.Cut(1, index) if(index)
lists_to_reserve.Cut(1, index)
return return
var/turf/T = packet[packetlen] var/turf/T = packet[packetlen]
T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE) T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
@@ -328,7 +329,6 @@ Used by the AI doomsday and the self-destruct nuke.
turf_reservations = SSmapping.turf_reservations turf_reservations = SSmapping.turf_reservations
used_turfs = SSmapping.used_turfs used_turfs = SSmapping.used_turfs
holodeck_templates = SSmapping.holodeck_templates holodeck_templates = SSmapping.holodeck_templates
transit = SSmapping.transit
areas_in_z = SSmapping.areas_in_z areas_in_z = SSmapping.areas_in_z
config = SSmapping.config config = SSmapping.config
@@ -663,6 +663,12 @@ GLOBAL_LIST_EMPTY(the_station_areas)
message_admins("Loading [away_name] failed!") message_admins("Loading [away_name] failed!")
return return
/// Adds a new reservation z level. A bit of space that can be handed out on request
/// Of note, reservations default to transit turfs, to make their most common use, shuttles, faster
/datum/controller/subsystem/mapping/proc/add_reservation_zlevel(for_shuttles)
num_of_res_levels++
return add_new_zlevel("Transit/Reserved #[num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE))
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) /datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override)
UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs) UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type var/datum/turf_reservation/reserve = new type
@@ -673,8 +679,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
if(reserve.Reserve(width, height, i)) if(reserve.Reserve(width, height, i))
return reserve return reserve
//If we didn't return at this point, theres a good chance we ran out of room on the exisiting reserved z levels, so lets try a new one //If we didn't return at this point, theres a good chance we ran out of room on the exisiting reserved z levels, so lets try a new one
num_of_res_levels += 1 var/datum/space_level/newReserved = add_reservation_zlevel()
var/datum/space_level/newReserved = add_new_zlevel("Transit/Reserved [num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE))
initialize_reserved_level(newReserved.z_value) initialize_reserved_level(newReserved.z_value)
if(reserve.Reserve(width, height, newReserved.z_value)) if(reserve.Reserve(width, height, newReserved.z_value))
return reserve return reserve
@@ -687,7 +692,9 @@ GLOBAL_LIST_EMPTY(the_station_areas)
return reserve return reserve
QDEL_NULL(reserve) QDEL_NULL(reserve)
//This is not for wiping reserved levels, use wipe_reservations() for that. ///Sets up a z level as reserved
///This is not for wiping reserved levels, use wipe_reservations() for that.
///If this is called after SSatom init, it will call Initialize on all turfs on the passed z, as its name promises
/datum/controller/subsystem/mapping/proc/initialize_reserved_level(z) /datum/controller/subsystem/mapping/proc/initialize_reserved_level(z)
UNTIL(!clearing_reserved_turfs) //regardless, lets add a check just in case. 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. 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.
@@ -697,11 +704,15 @@ GLOBAL_LIST_EMPTY(the_station_areas)
var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z)) var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z))
var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z)) var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z))
var/block = block(A, B) var/block = block(A, B)
for(var/t in block) for(var/turf/T as anything in block)
// No need to empty() these, because it's world init and they're // No need to empty() these, because they just got created and are already /turf/open/space/basic.
// already /turf/open/space/basic.
var/turf/T = t
T.flags_1 |= UNUSED_RESERVATION_TURF T.flags_1 |= UNUSED_RESERVATION_TURF
CHECK_TICK
// Gotta create these suckers if we've not done so already
if(SSatoms.initialized)
SSatoms.InitializeAtoms(Z_TURFS(z))
unused_turfs["[z]"] = block unused_turfs["[z]"] = block
reservation_ready["[z]"] = TRUE reservation_ready["[z]"] = TRUE
clearing_reserved_turfs = FALSE clearing_reserved_turfs = FALSE

View File

@@ -1,4 +1,10 @@
#define MAX_TRANSIT_REQUEST_RETRIES 10 #define MAX_TRANSIT_REQUEST_RETRIES 10
/// How many turfs to allow before we stop blocking transit requests
#define MAX_TRANSIT_TILE_COUNT (150 ** 2)
/// How many turfs to allow before we start freeing up existing "soft reserved" transit docks
/// If we're under load we want to allow for cycling, but if not we want to preserve already generated docks for use
#define SOFT_TRANSIT_RESERVATION_THRESHOLD (100 ** 2)
SUBSYSTEM_DEF(shuttle) SUBSYSTEM_DEF(shuttle)
name = "Shuttle" name = "Shuttle"
@@ -25,6 +31,8 @@ SUBSYSTEM_DEF(shuttle)
var/list/transit_requesters = list() var/list/transit_requesters = list()
/// An associative list of the mobile docking ports that have failed a transit request, with the amount of times they've actually failed that transit request, up to MAX_TRANSIT_REQUEST_RETRIES /// An associative list of the mobile docking ports that have failed a transit request, with the amount of times they've actually failed that transit request, up to MAX_TRANSIT_REQUEST_RETRIES
var/list/transit_request_failures = list() var/list/transit_request_failures = list()
/// How many turfs our shuttles are currently utilizing in reservation space
var/transit_utilized = 0
/** /**
* Emergency shuttle stuff * Emergency shuttle stuff
@@ -192,6 +200,11 @@ SUBSYSTEM_DEF(shuttle)
// This next one removes transit docks/zones that aren't // This next one removes transit docks/zones that aren't
// immediately being used. This will mean that the zone creation // immediately being used. This will mean that the zone creation
// code will be running a lot. // code will be running a lot.
// If we're below the soft reservation threshold, don't clear the old space
// We're better off holding onto it for now
if(transit_utilized < SOFT_TRANSIT_RESERVATION_THRESHOLD)
continue
var/obj/docking_port/mobile/owner = T.owner var/obj/docking_port/mobile/owner = T.owner
if(owner) if(owner)
var/idle = owner.mode == SHUTTLE_IDLE var/idle = owner.mode == SHUTTLE_IDLE
@@ -204,7 +217,10 @@ SUBSYSTEM_DEF(shuttle)
if(!SSmapping.clearing_reserved_turfs) if(!SSmapping.clearing_reserved_turfs)
while(transit_requesters.len) while(transit_requesters.len)
var/requester = popleft(transit_requesters) var/requester = popleft(transit_requesters)
var/success = generate_transit_dock(requester) var/success = null
// Do not try and generate any transit if we're using more then our max already
if(transit_utilized < MAX_TRANSIT_TILE_COUNT)
success = generate_transit_dock(requester)
if(!success) // BACK OF THE QUEUE if(!success) // BACK OF THE QUEUE
transit_request_failures[requester]++ transit_request_failures[requester]++
if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES)
@@ -619,6 +635,7 @@ SUBSYSTEM_DEF(shuttle)
var/turf/midpoint = locate(transit_x, transit_y, bottomleft.z) var/turf/midpoint = locate(transit_x, transit_y, bottomleft.z)
if(!midpoint) if(!midpoint)
qdel(proposal)
return FALSE return FALSE
var/area/old_area = midpoint.loc var/area/old_area = midpoint.loc
old_area.turfs_to_uncontain += proposal.reserved_turfs old_area.turfs_to_uncontain += proposal.reserved_turfs
@@ -635,9 +652,18 @@ SUBSYSTEM_DEF(shuttle)
// Add 180, because ports point inwards, rather than outwards // Add 180, because ports point inwards, rather than outwards
new_transit_dock.setDir(angle2dir(dock_angle)) new_transit_dock.setDir(angle2dir(dock_angle))
// Proposals use 2 extra hidden tiles of space, from the cordons that surround them
transit_utilized += (proposal.width + 2) * (proposal.height + 2)
M.assigned_transit = new_transit_dock M.assigned_transit = new_transit_dock
RegisterSignal(proposal, COMSIG_PARENT_QDELETING, PROC_REF(transit_space_clearing))
return new_transit_dock return new_transit_dock
/// Gotta manage our space brother
/datum/controller/subsystem/shuttle/proc/transit_space_clearing(datum/turf_reservation/source)
SIGNAL_HANDLER
transit_utilized -= (source.width + 2) * (source.height + 2)
/datum/controller/subsystem/shuttle/Recover() /datum/controller/subsystem/shuttle/Recover()
initialized = SSshuttle.initialized initialized = SSshuttle.initialized
if (istype(SSshuttle.mobile_docking_ports)) if (istype(SSshuttle.mobile_docking_ports))
@@ -856,7 +882,7 @@ SUBSYSTEM_DEF(shuttle)
/datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template) /datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template)
. = FALSE . = FALSE
// Load shuttle template to a fresh block reservation. // Load shuttle template to a fresh block reservation.
preview_reservation = SSmapping.RequestBlockReservation(loading_template.width, loading_template.height, SSmapping.transit.z_value, /datum/turf_reservation/transit) preview_reservation = SSmapping.RequestBlockReservation(loading_template.width, loading_template.height, type = /datum/turf_reservation/transit)
if(!preview_reservation) if(!preview_reservation)
CRASH("failed to reserve an area for shuttle template loading") CRASH("failed to reserve an area for shuttle template loading")
var/turf/bottom_left = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords) var/turf/bottom_left = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords)

View File

@@ -101,12 +101,13 @@
datum_flags &= ~DF_USE_TAG //In case something tries to REF us datum_flags &= ~DF_USE_TAG //In case something tries to REF us
weak_reference = null //ensure prompt GCing of weakref. weak_reference = null //ensure prompt GCing of weakref.
var/list/timers = active_timers if(active_timers)
active_timers = null var/list/timers = active_timers
for(var/datum/timedevent/timer as anything in timers) active_timers = null
if (timer.spent && !(timer.flags & TIMER_DELETE_ME)) for(var/datum/timedevent/timer as anything in timers)
continue if (timer.spent && !(timer.flags & TIMER_DELETE_ME))
qdel(timer) continue
qdel(timer)
#ifdef REFERENCE_TRACKING #ifdef REFERENCE_TRACKING
#ifdef REFERENCE_TRACKING_DEBUG #ifdef REFERENCE_TRACKING_DEBUG

View File

@@ -324,9 +324,10 @@
overlays.Cut() overlays.Cut()
LAZYNULL(managed_overlays) LAZYNULL(managed_overlays)
if(ai_controller)
QDEL_NULL(ai_controller) QDEL_NULL(ai_controller)
QDEL_NULL(light) if(light)
QDEL_NULL(light)
if (length(light_sources)) if (length(light_sources))
light_sources.Cut() light_sources.Cut()
@@ -1075,15 +1076,6 @@
/atom/proc/handle_atom_del(atom/deleting_atom) /atom/proc/handle_atom_del(atom/deleting_atom)
SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, deleting_atom) SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, deleting_atom)
/**
* called when the turf the atom resides on is ChangeTurfed
*
* Default behaviour is to loop through atom contents and call their HandleTurfChange() proc
*/
/atom/proc/HandleTurfChange(turf/changing_turf)
for(var/atom/current_atom as anything in src)
current_atom.HandleTurfChange(changing_turf)
/** /**
* the vision impairment to give to the mob whose perspective is set to that atom * the vision impairment to give to the mob whose perspective is set to that atom
* *

View File

@@ -244,11 +244,12 @@
if(!checked_turf) if(!checked_turf)
continue continue
if(isclosedturf(checked_turf))
RegisterSignal(checked_turf, COMSIG_TURF_CHANGE, PROC_REF(adjacent_change))
RegisterSignal(checked_turf, COMSIG_TURF_EXPOSE, PROC_REF(process_results))
if(!isopenturf(checked_turf))
continue continue
process_results(checked_turf) process_results(checked_turf)
RegisterSignal(checked_turf, COMSIG_TURF_EXPOSE, PROC_REF(process_results))
/obj/machinery/door/firedoor/proc/unregister_adjacent_turfs(atom/old_loc) /obj/machinery/door/firedoor/proc/unregister_adjacent_turfs(atom/old_loc)
if(!loc) if(!loc)
@@ -262,8 +263,14 @@
if(!checked_turf) if(!checked_turf)
continue continue
UnregisterSignal(checked_turf, COMSIG_TURF_CHANGE)
UnregisterSignal(checked_turf, COMSIG_TURF_EXPOSE) UnregisterSignal(checked_turf, COMSIG_TURF_EXPOSE)
// If a turf adjacent to us changes, recalc our affecting areas when it's done yeah?
/obj/machinery/door/firedoor/proc/adjacent_change(turf/changed, path, list/new_baseturfs, flags, list/post_change_callbacks)
SIGNAL_HANDLER
post_change_callbacks += CALLBACK(src, PROC_REF(CalculateAffectingAreas))
/obj/machinery/door/firedoor/proc/check_atmos(turf/checked_turf) /obj/machinery/door/firedoor/proc/check_atmos(turf/checked_turf)
var/datum/gas_mixture/environment = checked_turf.return_air() var/datum/gas_mixture/environment = checked_turf.return_air()

View File

@@ -9,6 +9,10 @@
. = ..() . = ..()
if(turf_loc_check && (!isturf(loc) || NeverShouldHaveComeHere(loc))) if(turf_loc_check && (!isturf(loc) || NeverShouldHaveComeHere(loc)))
return INITIALIZE_HINT_QDEL return INITIALIZE_HINT_QDEL
var/static/list/loc_connections = list(
COMSIG_TURF_CHANGED = PROC_REF(handle_turf_change),
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/decal/blob_act(obj/structure/blob/B) /obj/effect/decal/blob_act(obj/structure/blob/B)
if(B && B.loc == loc) if(B && B.loc == loc)
@@ -24,9 +28,12 @@
if(!(resistance_flags & FIRE_PROOF)) //non fire proof decal or being burned by lava if(!(resistance_flags & FIRE_PROOF)) //non fire proof decal or being burned by lava
qdel(src) qdel(src)
/obj/effect/decal/HandleTurfChange(turf/T) /obj/effect/decal/proc/handle_turf_change(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks)
..() SIGNAL_HANDLER
if(T == loc && NeverShouldHaveComeHere(T)) post_change_callbacks += CALLBACK(src, PROC_REF(sanity_check_self))
/obj/effect/decal/proc/sanity_check_self(turf/changed)
if(changed == loc && NeverShouldHaveComeHere(changed))
qdel(src) qdel(src)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -82,8 +82,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
lgroup.remove_from_group(src) lgroup.remove_from_group(src)
//SKYRAT EDIT END //SKYRAT EDIT END
var/old_rcd_memory = rcd_memory var/old_rcd_memory = rcd_memory
var/old_space_lit = space_lit
var/old_explosion_throw_details = explosion_throw_details var/old_explosion_throw_details = explosion_throw_details
var/old_opacity = opacity
// I'm so sorry brother
// This is used for a starlight optimization
var/old_light_range = light_range
// We get just the bits of explosive_resistance that aren't the turf // We get just the bits of explosive_resistance that aren't the turf
var/old_explosive_resistance = explosive_resistance - get_explosive_block() var/old_explosive_resistance = explosive_resistance - get_explosive_block()
var/old_lattice_underneath = lattice_underneath var/old_lattice_underneath = lattice_underneath
@@ -137,17 +140,13 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
lattice_underneath = old_lattice_underneath lattice_underneath = old_lattice_underneath
var/area/our_area = new_turf.loc
if(new_turf.space_lit && !our_area.area_has_base_lighting)
// We are guarenteed to have these overlays because of how generation works
var/mutable_appearance/overlay = GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]
new_turf.add_overlay(overlay)
else if (old_space_lit && !our_area.area_has_base_lighting)
var/mutable_appearance/overlay = GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]
new_turf.cut_overlay(overlay)
if(SSlighting.initialized) if(SSlighting.initialized)
new_turf.lighting_object = old_lighting_object // Space tiles should never have lighting objects
if(!space_lit)
// Should have a lighting object if we never had one
lighting_object = old_lighting_object || new /datum/lighting_object(src)
else if (old_lighting_object)
qdel(old_lighting_object, force = TRUE)
directional_opacity = old_directional_opacity directional_opacity = old_directional_opacity
recalculate_directional_opacity() recalculate_directional_opacity()
@@ -155,8 +154,28 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
if(lighting_object && !lighting_object.needs_update) if(lighting_object && !lighting_object.needs_update)
lighting_object.update() lighting_object.update()
// If we're space, then we're either lit, or not, and impacting our neighbors, or not
if(isspaceturf(src) && CONFIG_GET(flag/starlight))
var/turf/open/space/lit_turf = src
// This also counts as a removal, so we need to do a full rebuild
if(!ispath(old_type, /turf/open/space))
lit_turf.update_starlight()
for(var/turf/open/space/space_tile in RANGE_TURFS(1, src) - src)
space_tile.update_starlight()
else if(old_light_range)
lit_turf.enable_starlight()
// If we're a cordon we count against a light, but also don't produce any ourselves
else if (istype(src, /turf/cordon) && CONFIG_GET(flag/starlight))
// This counts as removing a source of starlight, so we need to update the space tile to inform it
if(!ispath(old_type, /turf/open/space))
for(var/turf/open/space/space_tile in RANGE_TURFS(1, src))
space_tile.update_starlight()
// If we're not either, but were formerly a space turf, then we want light
else if(ispath(old_type, /turf/open/space) && CONFIG_GET(flag/starlight))
for(var/turf/open/space/space_tile in RANGE_TURFS(1, src)) for(var/turf/open/space/space_tile in RANGE_TURFS(1, src))
space_tile.update_starlight() space_tile.enable_starlight()
//SKYRAT EDIT ADDITION //SKYRAT EDIT ADDITION
if(old_liquids) if(old_liquids)
if(new_turf.liquids) if(new_turf.liquids)
@@ -182,12 +201,17 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
qdel(old_liquids, TRUE) qdel(old_liquids, TRUE)
//SKYRAT EDIT END //SKYRAT EDIT END
if(old_opacity != opacity && SSticker)
GLOB.cameranet.bareMajorChunkChange(src)
// We will only run this logic if the tile is not on the prime z layer, since we use area overlays to cover that // We will only run this logic if the tile is not on the prime z layer, since we use area overlays to cover that
if(SSmapping.z_level_to_plane_offset[z]) if(SSmapping.z_level_to_plane_offset[z])
var/area/our_area = new_turf.loc
if(our_area.lighting_effects) if(our_area.lighting_effects)
new_turf.add_overlay(our_area.lighting_effects[SSmapping.z_level_to_plane_offset[z] + 1]) new_turf.add_overlay(our_area.lighting_effects[SSmapping.z_level_to_plane_offset[z] + 1])
if(flags_1 & INITIALIZED_1) // only queue for smoothing if SSatom initialized us // only queue for smoothing if SSatom initialized us, and we'd be changing smoothing state
if(flags_1 & INITIALIZED_1)
QUEUE_SMOOTH_NEIGHBORS(src) QUEUE_SMOOTH_NEIGHBORS(src)
QUEUE_SMOOTH(src) QUEUE_SMOOTH(src)
@@ -224,7 +248,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
if(pollution) if(pollution)
qdel(pollution) qdel(pollution)
//SKYRAT EDIT END //SKYRAT EDIT END
SSair.remove_from_active(src) //Clean up wall excitement, and refresh excited groups if(excited || excited_group)
SSair.remove_from_active(src) //Clean up wall excitement, and refresh excited groups
if(ispath(path,/turf/closed) || ispath(path,/turf/cordon)) if(ispath(path,/turf/closed) || ispath(path,/turf/cordon))
flags |= CHANGETURF_RECALC_ADJACENT flags |= CHANGETURF_RECALC_ADJACENT
return ..() return ..()
@@ -238,13 +263,6 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
SSair.add_to_active(src) SSair.add_to_active(src)
else //In effect, I want closed turfs to make their tile active when sheered, but we need to queue it since they have no adjacent turfs else //In effect, I want closed turfs to make their tile active when sheered, but we need to queue it since they have no adjacent turfs
CALCULATE_ADJACENT_TURFS(src, (!(ispath(oldType, /turf/closed) && isopenturf(src)) ? NORMAL_TURF : MAKE_ACTIVE)) CALCULATE_ADJACENT_TURFS(src, (!(ispath(oldType, /turf/closed) && isopenturf(src)) ? NORMAL_TURF : MAKE_ACTIVE))
//update firedoor adjacency
var/list/turfs_to_check = get_adjacent_open_turfs(src) | src
for(var/turf/check_turf in turfs_to_check)
for(var/obj/machinery/door/firedoor/FD in check_turf)
FD.CalculateAffectingAreas()
HandleTurfChange(src)
/turf/open/AfterChange(flags, oldType) /turf/open/AfterChange(flags, oldType)
..() ..()

View File

@@ -16,6 +16,8 @@
/turf/open/openspace/airless/planetary /turf/open/openspace/airless/planetary
planetary_atmos = TRUE planetary_atmos = TRUE
// Reminder, any behavior code written here needs to be duped to /turf/open/space/openspace
// I am so sorry
/turf/open/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker /turf/open/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker
. = ..() . = ..()
RegisterSignal(src, COMSIG_ATOM_INITIALIZED_ON, PROC_REF(on_atom_created)) RegisterSignal(src, COMSIG_ATOM_INITIALIZED_ON, PROC_REF(on_atom_created))

View File

@@ -8,6 +8,7 @@
temperature = TCMB temperature = TCMB
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 700000 heat_capacity = 700000
var/starlight_source_count = 0
var/destination_z var/destination_z
var/destination_x var/destination_x
@@ -101,15 +102,23 @@
/turf/open/space/remove_air(amount) /turf/open/space/remove_air(amount)
return null return null
/// Updates starlight. Called when we're unsure of a turf's starlight state
/// Returns TRUE if we succeed, FALSE otherwise
/turf/open/space/proc/update_starlight() /turf/open/space/proc/update_starlight()
if(CONFIG_GET(flag/starlight)) for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm
for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm // I've got a lot of cordons near spaceturfs, be good kids
if(isspaceturf(t)) if(isspaceturf(t) || istype(t, /turf/cordon))
//let's NOT update this that much pls //let's NOT update this that much pls
continue continue
set_light(2) enable_starlight()
return return TRUE
set_light(0) set_light(0)
return FALSE
/// Turns on the stars, if they aren't already
/turf/open/space/proc/enable_starlight()
if(!light_range)
set_light(2)
/turf/open/space/attack_paw(mob/user, list/modifiers) /turf/open/space/attack_paw(mob/user, list/modifiers)
return attack_hand(user, modifiers) return attack_hand(user, modifiers)
@@ -271,16 +280,25 @@
return TRUE return TRUE
return FALSE return FALSE
/turf/open/space/openspace/update_starlight() /turf/open/space/openspace/enable_starlight()
if(!CONFIG_GET(flag/starlight))
return
var/turf/below = SSmapping.get_turf_below(src) var/turf/below = SSmapping.get_turf_below(src)
// Override = TRUE beacuse we could have our starlight updated many times without a failure, which'd trigger this
RegisterSignal(below, COMSIG_TURF_CHANGE, PROC_REF(on_below_change), override = TRUE)
if(!isspaceturf(below)) if(!isspaceturf(below))
return return
for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm set_light(2)
if(isspaceturf(t))
//let's NOT update this that much pls /turf/open/space/openspace/update_starlight()
continue . = ..()
set_light(2) if(.)
return return
set_light(0) // If we're here, the starlight is not to be
var/turf/below = SSmapping.get_turf_below(src)
UnregisterSignal(below, COMSIG_TURF_CHANGE)
/turf/open/space/openspace/proc/on_below_change(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks)
SIGNAL_HANDLER
if(isspaceturf(source) && !ispath(path, /turf/open/space))
set_light(2)
else if(!isspaceturf(source) && ispath(path, /turf/open/space))
set_light(0)

View File

@@ -15,9 +15,10 @@
for(var/atom/movable/movable in src) for(var/atom/movable/movable in src)
throw_atom(movable) throw_atom(movable)
/turf/open/space/transit/clear_signal_refs() /turf/open/space/transit/Destroy()
//Signals are NOT removed from turfs upon replacement, and we get replaced ALOT, so unregister our signal //Signals are NOT removed from turfs upon replacement, and we get replaced ALOT, so unregister our signal
UnregisterSignal(src, COMSIG_TURF_RESERVATION_RELEASED) UnregisterSignal(src, COMSIG_TURF_RESERVATION_RELEASED)
return ..()
/turf/open/space/transit/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) /turf/open/space/transit/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
. = ..() . = ..()

View File

@@ -147,10 +147,6 @@ GLOBAL_LIST_EMPTY(station_turfs)
if (smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK)) if (smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK))
QUEUE_SMOOTH(src) QUEUE_SMOOTH(src)
// visibilityChanged() will never hit any path with side effects during mapload
if (!mapload)
visibilityChanged()
for(var/atom/movable/content as anything in src) for(var/atom/movable/content as anything in src)
Entered(content, null) Entered(content, null)
@@ -186,12 +182,13 @@ GLOBAL_LIST_EMPTY(station_turfs)
if(!changing_turf) if(!changing_turf)
stack_trace("Incorrect turf deletion") stack_trace("Incorrect turf deletion")
changing_turf = FALSE changing_turf = FALSE
var/turf/T = SSmapping.get_turf_above(src) if(GET_LOWEST_STACK_OFFSET(z))
if(T) var/turf/T = SSmapping.get_turf_above(src)
T.multiz_turf_del(src, DOWN) if(T)
T = SSmapping.get_turf_below(src) T.multiz_turf_del(src, DOWN)
if(T) T = SSmapping.get_turf_below(src)
T.multiz_turf_del(src, UP) if(T)
T.multiz_turf_del(src, UP)
if(force) if(force)
..() ..()
//this will completely wipe turf state //this will completely wipe turf state
@@ -199,7 +196,6 @@ GLOBAL_LIST_EMPTY(station_turfs)
for(var/A in B.contents) for(var/A in B.contents)
qdel(A) qdel(A)
return return
visibilityChanged()
QDEL_LIST(blueprint_data) QDEL_LIST(blueprint_data)
flags_1 &= ~INITIALIZED_1 flags_1 &= ~INITIALIZED_1
requires_activation = FALSE requires_activation = FALSE

View File

@@ -28,9 +28,7 @@
/// Will update the light (duh). /// Will update the light (duh).
/// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf... /// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf...
/atom/proc/update_light() /atom/proc/update_light()
set waitfor = FALSE SHOULD_NOT_SLEEP(TRUE)
if (QDELETED(src))
return
if(light_system != STATIC_LIGHT) if(light_system != STATIC_LIGHT)
CRASH("update_light() for [src] with following light_system value: [light_system]") CRASH("update_light() for [src] with following light_system value: [light_system]")

View File

@@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
// Really this should be a global var or something, but lets not think about that yes? // Really this should be a global var or something, but lets not think about that yes?
if(CONFIG_GET(flag/starlight)) if(CONFIG_GET(flag/starlight))
for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf)) for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.update_starlight() space_tile.enable_starlight()
needs_update = TRUE needs_update = TRUE
SSlighting.objects_queue += src SSlighting.objects_queue += src

View File

@@ -7,6 +7,6 @@
for(var/turf/T as anything in A.get_contained_turfs()) for(var/turf/T as anything in A.get_contained_turfs())
if(T.space_lit) if(T.space_lit)
continue continue
new/datum/lighting_object(T) new /datum/lighting_object(T)
CHECK_TICK CHECK_TICK
CHECK_TICK CHECK_TICK

View File

@@ -14,7 +14,7 @@
if (lighting_object) if (lighting_object)
qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death
new/datum/lighting_object(src) new /datum/lighting_object(src)
// Used to get a scaled lumcount. // Used to get a scaled lumcount.
/turf/proc/get_lumcount(minlum = 0, maxlum = 1) /turf/proc/get_lumcount(minlum = 0, maxlum = 1)
@@ -81,19 +81,20 @@
reconsider_lights() reconsider_lights()
return return
directional_opacity = NONE directional_opacity = NONE
for(var/atom/movable/opacity_source as anything in opacity_sources) if(opacity_sources)
if(opacity_source.flags_1 & ON_BORDER_1) for(var/atom/movable/opacity_source as anything in opacity_sources)
directional_opacity |= opacity_source.dir if(opacity_source.flags_1 & ON_BORDER_1)
else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking. directional_opacity |= opacity_source.dir
directional_opacity = ALL_CARDINALS else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking.
break directional_opacity = ALL_CARDINALS
break
if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS)) if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS))
reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not. reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not.
///Transfer the lighting of one area to another ///Transfer the lighting of one area to another
/turf/proc/transfer_area_lighting(area/old_area, area/new_area) /turf/proc/transfer_area_lighting(area/old_area, area/new_area)
if(SSlighting.initialized) if(SSlighting.initialized && !space_lit)
if (new_area.static_lighting != old_area.static_lighting) if (new_area.static_lighting != old_area.static_lighting)
if (new_area.static_lighting) if (new_area.static_lighting)
lighting_build_overlay() lighting_build_overlay()
@@ -109,3 +110,7 @@
cut_overlay(old_area.lighting_effects[index]) cut_overlay(old_area.lighting_effects[index])
if(new_area.lighting_effects) if(new_area.lighting_effects)
add_overlay(new_area.lighting_effects[index]) add_overlay(new_area.lighting_effects[index])
// If we're changing into an area with no lighting, and we're lit, light ourselves
if(!new_area.lighting_effects && old_area.lighting_effects && space_lit)
overlays += GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]

View File

@@ -800,11 +800,11 @@ GLOBAL_LIST_EMPTY(map_model_default)
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile //The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
//first instance the /area and remove it from the members list //first instance the /area and remove it from the members list
index = members.len index = members.len
var/area/old_area
if(members[index] != /area/template_noop) if(members[index] != /area/template_noop)
var/area/area_instance
if(members_attributes[index] != default_list) if(members_attributes[index] != default_list)
world.preloader_setup(members_attributes[index], members[index])//preloader for assigning set variables on atom creation world.preloader_setup(members_attributes[index], members[index])//preloader for assigning set variables on atom creation
area_instance = loaded_areas[members[index]] var/area/area_instance = loaded_areas[members[index]]
if(!area_instance) if(!area_instance)
var/area_type = members[index] var/area_type = members[index]
// If this parsed map doesn't have that area already, we check the global cache // If this parsed map doesn't have that area already, we check the global cache
@@ -817,7 +817,7 @@ GLOBAL_LIST_EMPTY(map_model_default)
loaded_areas[area_type] = area_instance loaded_areas[area_type] = area_instance
if(!new_z) if(!new_z)
var/area/old_area = crds.loc old_area = crds.loc
old_area.turfs_to_uncontain += crds old_area.turfs_to_uncontain += crds
area_instance.contained_turfs.Add(crds) area_instance.contained_turfs.Add(crds)
area_instance.contents.Add(crds) area_instance.contents.Add(crds)
@@ -845,6 +845,9 @@ GLOBAL_LIST_EMPTY(map_model_default)
if(GLOB.use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New() if(GLOB.use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
world.preloader_load(instance) world.preloader_load(instance)
// If this isn't template work, we didn't change our turf and we changed area, then we've gotta handle area lighting transfer
else if(!no_changeturf && old_area)
crds.transfer_area_lighting(old_area, crds.loc)
MAPLOADING_CHECK_TICK MAPLOADING_CHECK_TICK
//finally instance all remainings objects/mobs //finally instance all remainings objects/mobs

View File

@@ -19,6 +19,8 @@
manage_z_level(S, filled_with_space = FALSE) manage_z_level(S, filled_with_space = FALSE)
generate_z_level_linkages() // Default Zs don't use add_new_zlevel() so they don't automatically generate z-linkages. generate_z_level_linkages() // Default Zs don't use add_new_zlevel() so they don't automatically generate z-linkages.
/// Generates a real, honest to god new z level. Will create the actual space, and also generate a datum that holds info about the new plot of land
/// Accepts the name, traits list, datum type, and if we should manage the turfs we create
/datum/controller/subsystem/mapping/proc/add_new_zlevel(name, traits = list(), z_type = /datum/space_level, contain_turfs = TRUE) /datum/controller/subsystem/mapping/proc/add_new_zlevel(name, traits = list(), z_type = /datum/space_level, contain_turfs = TRUE)
UNTIL(!adding_new_zlevel) UNTIL(!adding_new_zlevel)
adding_new_zlevel = TRUE adding_new_zlevel = TRUE

View File

@@ -42,8 +42,11 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
/datum/cameranet/proc/chunkGenerated(x, y, z) /datum/cameranet/proc/chunkGenerated(x, y, z)
x = GET_CHUNK_COORD(x) x = GET_CHUNK_COORD(x)
y = GET_CHUNK_COORD(y) y = GET_CHUNK_COORD(y)
var/turf/lowest = get_lowest_turf(locate(x, y, z)) if(GET_LOWEST_STACK_OFFSET(z) != 0)
return chunks["[x],[y],[lowest.z]"] var/turf/lowest = get_lowest_turf(locate(x, y, z))
return chunks["[x],[y],[lowest.z]"]
return chunks["[x],[y],[z]"]
// Returns the chunk in the x, y, z. // Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that. // If there is no chunk, it creates a new chunk and returns that.
@@ -150,6 +153,18 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
chunk.cameras["[T.z]"] |= c chunk.cameras["[T.z]"] |= c
chunk.hasChanged(update_delay_buffer = update_delay_buffer) chunk.hasChanged(update_delay_buffer = update_delay_buffer)
/// A faster, turf only version of [/datum/cameranet/proc/majorChunkChange]
/// For use in sensitive code, be careful with it
/datum/cameranet/proc/bareMajorChunkChange(turf/changed)
var/x1 = max(1, changed.x - (CHUNK_SIZE / 2))
var/y1 = max(1, changed.y - (CHUNK_SIZE / 2))
var/x2 = min(world.maxx, changed.x + (CHUNK_SIZE / 2))
var/y2 = min(world.maxy, changed.y + (CHUNK_SIZE / 2))
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
var/datum/camerachunk/chunk = chunkGenerated(x, y, changed.z)
chunk?.hasChanged()
/// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0. /// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/cameranet/proc/checkCameraVis(mob/living/target) /datum/cameranet/proc/checkCameraVis(mob/living/target)
var/turf/position = get_turf(target) var/turf/position = get_turf(target)