diff --git a/code/__DEFINES/stat_tracking.dm b/code/__DEFINES/stat_tracking.dm index 810a313ac31..d143e5df4c7 100644 --- a/code/__DEFINES/stat_tracking.dm +++ b/code/__DEFINES/stat_tracking.dm @@ -15,7 +15,7 @@ #define INIT_COST(costs, counting) \ var/list/_costs = costs; \ 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 // Good for debug stuff, and for running before globals init @@ -31,16 +31,16 @@ costs = hidden_static_list_for_fun1; \ counting = hidden_static_list_for_fun2 ; \ } \ - usage = TICK_USAGE; + _usage = TICK_USAGE; #define SET_COST(category) \ do { \ - var/cost = TICK_USAGE; \ - _costs[category] += TICK_DELTA_TO_MS(cost - usage);\ + var/_cost = TICK_USAGE; \ + _costs[category] += TICK_DELTA_TO_MS(_cost - _usage);\ _counting[category] += 1; \ } while(FALSE); \ - usage = TICK_USAGE; + _usage = TICK_USAGE; #define SET_COST_LINE(...) SET_COST("[__LINE__]") @@ -62,4 +62,5 @@ ##proc(filename, costs, counts); \ } \ } \ - } while (FALSE); + } while (FALSE); \ + _usage = TICK_USAGE; diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index cbaa1b906d8..7cc953691e7 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -348,19 +348,27 @@ ///Returns the open turf next to the center in a specific direction /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)) return get_turf ///Returns a list with all the adjacent open turfs. Clears the list of nulls in the end. /proc/get_adjacent_open_turfs(atom/center) - . = list( - get_open_turf_in_dir(center, NORTH), - get_open_turf_in_dir(center, SOUTH), - get_open_turf_in_dir(center, EAST), - get_open_turf_in_dir(center, WEST) - ) - list_clear_nulls(.) + var/list/hand_back = list() + // Inlined get_open_turf_in_dir, just to be fast + var/turf/open/new_turf = get_step(center, NORTH) + if(istype(new_turf)) + hand_back += new_turf + new_turf = get_step(center, SOUTH) + 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 /proc/get_adjacent_open_areas(atom/center) diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index d10724a36af..b53fd6b2a80 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -148,13 +148,13 @@ SUBSYSTEM_DEF(mapping) #endif // Run map generation after ruin generation to prevent issues run_map_generation() - // Add the transit level - transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE)) + // Add the first transit level + var/datum/space_level/base_transit = add_reservation_zlevel() require_area_resort() // Set up Z-level transitions. setup_map_transitions() generate_station_area_list() - initialize_reserved_level(transit.z_value) + initialize_reserved_level(base_transit.z_value) calculate_default_z_level_gravities() return SS_INIT_SUCCESS @@ -171,7 +171,8 @@ SUBSYSTEM_DEF(mapping) var/packetlen = length(packet) while(packetlen) if(MC_TICK_CHECK) - lists_to_reserve.Cut(1, index) + if(index) + lists_to_reserve.Cut(1, index) return var/turf/T = packet[packetlen] 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 used_turfs = SSmapping.used_turfs holodeck_templates = SSmapping.holodeck_templates - transit = SSmapping.transit areas_in_z = SSmapping.areas_in_z config = SSmapping.config @@ -647,6 +647,12 @@ GLOBAL_LIST_EMPTY(the_station_areas) message_admins("Loading [away_name] failed!") 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) UNTIL((!z || reservation_ready["[z]"]) && !clearing_reserved_turfs) var/datum/turf_reservation/reserve = new type @@ -657,8 +663,7 @@ GLOBAL_LIST_EMPTY(the_station_areas) if(reserve.Reserve(width, height, i)) 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 - num_of_res_levels += 1 - var/datum/space_level/newReserved = add_new_zlevel("Transit/Reserved [num_of_res_levels]", list(ZTRAIT_RESERVED = TRUE)) + var/datum/space_level/newReserved = add_reservation_zlevel() initialize_reserved_level(newReserved.z_value) if(reserve.Reserve(width, height, newReserved.z_value)) return reserve @@ -671,7 +676,9 @@ GLOBAL_LIST_EMPTY(the_station_areas) return 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) 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. @@ -681,11 +688,15 @@ GLOBAL_LIST_EMPTY(the_station_areas) 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/block = block(A, B) - for(var/t in block) - // No need to empty() these, because it's world init and they're - // already /turf/open/space/basic. - var/turf/T = t + for(var/turf/T as anything in block) + // No need to empty() these, because they just got created and are already /turf/open/space/basic. 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 reservation_ready["[z]"] = TRUE clearing_reserved_turfs = FALSE diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 783915b2569..0e9d4fdce03 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -1,4 +1,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) name = "Shuttle" @@ -25,6 +31,8 @@ SUBSYSTEM_DEF(shuttle) 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 var/list/transit_request_failures = list() + /// How many turfs our shuttles are currently utilizing in reservation space + var/transit_utilized = 0 /** * Emergency shuttle stuff @@ -199,6 +207,11 @@ SUBSYSTEM_DEF(shuttle) // This next one removes transit docks/zones that aren't // immediately being used. This will mean that the zone creation // 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 if(owner) var/idle = owner.mode == SHUTTLE_IDLE @@ -211,7 +224,10 @@ SUBSYSTEM_DEF(shuttle) if(!SSmapping.clearing_reserved_turfs) while(transit_requesters.len) 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 transit_request_failures[requester]++ if(transit_request_failures[requester] < MAX_TRANSIT_REQUEST_RETRIES) @@ -614,6 +630,7 @@ SUBSYSTEM_DEF(shuttle) var/turf/midpoint = locate(transit_x, transit_y, bottomleft.z) if(!midpoint) + qdel(proposal) return FALSE var/area/old_area = midpoint.loc old_area.turfs_to_uncontain += proposal.reserved_turfs @@ -630,9 +647,18 @@ SUBSYSTEM_DEF(shuttle) // Add 180, because ports point inwards, rather than outwards 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 + RegisterSignal(proposal, COMSIG_PARENT_QDELETING, PROC_REF(transit_space_clearing)) + 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() initialized = SSshuttle.initialized if (istype(SSshuttle.mobile_docking_ports)) @@ -851,7 +877,7 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/load_template(datum/map_template/shuttle/loading_template) . = FALSE // 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) CRASH("failed to reserve an area for shuttle template loading") var/turf/bottom_left = TURF_FROM_COORDS_LIST(preview_reservation.bottom_left_coords) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 13d44e4afaa..9e42adcda2b 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -105,12 +105,13 @@ datum_flags &= ~DF_USE_TAG //In case something tries to REF us weak_reference = null //ensure prompt GCing of weakref. - var/list/timers = active_timers - active_timers = null - for(var/datum/timedevent/timer as anything in timers) - if (timer.spent && !(timer.flags & TIMER_DELETE_ME)) - continue - qdel(timer) + if(active_timers) + var/list/timers = active_timers + active_timers = null + for(var/datum/timedevent/timer as anything in timers) + if (timer.spent && !(timer.flags & TIMER_DELETE_ME)) + continue + qdel(timer) #ifdef REFERENCE_TRACKING #ifdef REFERENCE_TRACKING_DEBUG diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 9ac44b4460d..884f87c7190 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -322,9 +322,10 @@ overlays.Cut() LAZYNULL(managed_overlays) - - QDEL_NULL(ai_controller) - QDEL_NULL(light) + if(ai_controller) + QDEL_NULL(ai_controller) + if(light) + QDEL_NULL(light) if (length(light_sources)) light_sources.Cut() @@ -1044,15 +1045,6 @@ /atom/proc/handle_atom_del(atom/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 * diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 68f9da9f83c..e01aab37dd7 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -244,11 +244,12 @@ if(!checked_turf) 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 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) if(!loc) @@ -262,8 +263,14 @@ if(!checked_turf) continue + UnregisterSignal(checked_turf, COMSIG_TURF_CHANGE) 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) var/datum/gas_mixture/environment = checked_turf.return_air() if(!environment) diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 40e622b5225..399c81455d0 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -9,6 +9,10 @@ . = ..() if(turf_loc_check && (!isturf(loc) || NeverShouldHaveComeHere(loc))) 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) if(B && B.loc == loc) @@ -24,9 +28,12 @@ if(!(resistance_flags & FIRE_PROOF)) //non fire proof decal or being burned by lava qdel(src) -/obj/effect/decal/HandleTurfChange(turf/T) - ..() - if(T == loc && NeverShouldHaveComeHere(T)) +/obj/effect/decal/proc/handle_turf_change(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks) + SIGNAL_HANDLER + 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) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 3a1cc8aaac3..b5ccc15b3db 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -77,8 +77,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/old_directional_opacity = directional_opacity var/old_dynamic_lumcount = dynamic_lumcount var/old_rcd_memory = rcd_memory - var/old_space_lit = space_lit 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 var/old_explosive_resistance = explosive_resistance - get_explosive_block() var/old_lattice_underneath = lattice_underneath @@ -132,17 +135,13 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( 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) - 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 recalculate_directional_opacity() @@ -150,15 +149,40 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(lighting_object && !lighting_object.needs_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)) - space_tile.update_starlight() + space_tile.enable_starlight() + + 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 if(SSmapping.z_level_to_plane_offset[z]) + var/area/our_area = new_turf.loc if(our_area.lighting_effects) 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(src) @@ -185,7 +209,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(stashed_group.should_display || SSair.display_all_groups) stashed_group.display_turf(new_turf) else - 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)) flags |= CHANGETURF_RECALC_ADJACENT return ..() @@ -199,13 +224,6 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( 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 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) ..() diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index f24d5d8fb52..ba16fc0872c 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -16,6 +16,8 @@ /turf/open/openspace/airless/planetary 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 . = ..() RegisterSignal(src, COMSIG_ATOM_INITIALIZED_ON, PROC_REF(on_atom_created)) diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index f2ae490bb0a..0a9202ba00c 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -8,6 +8,7 @@ temperature = TCMB thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT heat_capacity = 700000 + var/starlight_source_count = 0 var/destination_z var/destination_x @@ -101,15 +102,23 @@ /turf/open/space/remove_air(amount) 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() - if(CONFIG_GET(flag/starlight)) - for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm - if(isspaceturf(t)) - //let's NOT update this that much pls - continue - set_light(2) - return - set_light(0) + 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) || istype(t, /turf/cordon)) + //let's NOT update this that much pls + continue + enable_starlight() + return TRUE + 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) return attack_hand(user, modifiers) @@ -243,7 +252,6 @@ /turf/open/space/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker . = ..() icon_state = "invisible" - update_starlight() return INITIALIZE_HINT_LATELOAD /turf/open/space/openspace/LateInitialize() @@ -284,16 +292,25 @@ return TRUE return FALSE -/turf/open/space/openspace/update_starlight() - if(!CONFIG_GET(flag/starlight)) - return +/turf/open/space/openspace/enable_starlight() 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)) return - for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm - if(isspaceturf(t)) - //let's NOT update this that much pls - continue - set_light(2) + set_light(2) + +/turf/open/space/openspace/update_starlight() + . = ..() + if(.) 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) diff --git a/code/game/turfs/open/space/transit.dm b/code/game/turfs/open/space/transit.dm index 74ba0e6fb0a..2f4c49fe5b1 100644 --- a/code/game/turfs/open/space/transit.dm +++ b/code/game/turfs/open/space/transit.dm @@ -15,9 +15,10 @@ for(var/atom/movable/movable in src) 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 UnregisterSignal(src, COMSIG_TURF_RESERVATION_RELEASED) + return ..() /turf/open/space/transit/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) . = ..() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 4bbe3f8f2cc..17da71ea408 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -147,10 +147,6 @@ GLOBAL_LIST_EMPTY(station_turfs) if (smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK)) 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) Entered(content, null) @@ -186,12 +182,13 @@ GLOBAL_LIST_EMPTY(station_turfs) if(!changing_turf) stack_trace("Incorrect turf deletion") changing_turf = FALSE - var/turf/T = SSmapping.get_turf_above(src) - if(T) - T.multiz_turf_del(src, DOWN) - T = SSmapping.get_turf_below(src) - if(T) - T.multiz_turf_del(src, UP) + if(GET_LOWEST_STACK_OFFSET(z)) + var/turf/T = SSmapping.get_turf_above(src) + if(T) + T.multiz_turf_del(src, DOWN) + T = SSmapping.get_turf_below(src) + if(T) + T.multiz_turf_del(src, UP) if(force) ..() //this will completely wipe turf state @@ -199,7 +196,6 @@ GLOBAL_LIST_EMPTY(station_turfs) for(var/A in B.contents) qdel(A) return - visibilityChanged() QDEL_LIST(blueprint_data) flags_1 &= ~INITIALIZED_1 requires_activation = FALSE diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index f0487b86b1a..e11981aacee 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -28,9 +28,7 @@ /// Will update the light (duh). /// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf... /atom/proc/update_light() - set waitfor = FALSE - if (QDELETED(src)) - return + SHOULD_NOT_SLEEP(TRUE) if(light_system != STATIC_LIGHT) CRASH("update_light() for [src] with following light_system value: [light_system]") diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index cd590008720..5f7b16eb7d1 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -33,7 +33,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? if(CONFIG_GET(flag/starlight)) for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf)) - space_tile.update_starlight() + space_tile.enable_starlight() needs_update = TRUE SSlighting.objects_queue += src diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index 541569be0fb..d6bf19711ef 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -7,6 +7,6 @@ for(var/turf/T as anything in A.get_contained_turfs()) if(T.space_lit) continue - new/datum/lighting_object(T) + new /datum/lighting_object(T) CHECK_TICK CHECK_TICK diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 8692fc475dc..d093961411e 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -14,7 +14,7 @@ if (lighting_object) 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. /turf/proc/get_lumcount(minlum = 0, maxlum = 1) @@ -81,19 +81,20 @@ reconsider_lights() return directional_opacity = NONE - for(var/atom/movable/opacity_source as anything in opacity_sources) - if(opacity_source.flags_1 & ON_BORDER_1) - directional_opacity |= opacity_source.dir - else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking. - directional_opacity = ALL_CARDINALS - break + if(opacity_sources) + for(var/atom/movable/opacity_source as anything in opacity_sources) + if(opacity_source.flags_1 & ON_BORDER_1) + directional_opacity |= opacity_source.dir + else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking. + directional_opacity = ALL_CARDINALS + break 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. ///Transfer the lighting of one area to another /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) lighting_build_overlay() @@ -109,3 +110,7 @@ cut_overlay(old_area.lighting_effects[index]) if(new_area.lighting_effects) 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] diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 4eb1512191a..f6538d4ec1d 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -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 //first instance the /area and remove it from the members list index = members.len + var/area/old_area if(members[index] != /area/template_noop) - var/area/area_instance if(members_attributes[index] != default_list) 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) var/area_type = members[index] // 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 if(!new_z) - var/area/old_area = crds.loc + old_area = crds.loc old_area.turfs_to_uncontain += crds area_instance.contained_turfs.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() 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 //finally instance all remainings objects/mobs diff --git a/code/modules/mapping/space_management/zlevel_manager.dm b/code/modules/mapping/space_management/zlevel_manager.dm index 1c2e73ab003..b7664f09ff2 100644 --- a/code/modules/mapping/space_management/zlevel_manager.dm +++ b/code/modules/mapping/space_management/zlevel_manager.dm @@ -19,6 +19,8 @@ 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. +/// 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) UNTIL(!adding_new_zlevel) adding_new_zlevel = TRUE diff --git a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm index 27920dc2513..facffbc5cce 100644 --- a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm +++ b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm @@ -42,8 +42,11 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new) /datum/cameranet/proc/chunkGenerated(x, y, z) x = GET_CHUNK_COORD(x) y = GET_CHUNK_COORD(y) - var/turf/lowest = get_lowest_turf(locate(x, y, z)) - return chunks["[x],[y],[lowest.z]"] + if(GET_LOWEST_STACK_OFFSET(z) != 0) + 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. // 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.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. /datum/cameranet/proc/checkCameraVis(mob/living/target) var/turf/position = get_turf(target)