mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-21 23:24:20 +00:00
3591 individual conflicts Update build.js Update install_node.sh Update byond.js oh my fucking god hat slow huh holy shit we all fall down 2 more I missed 2900 individual conflicts 2700 Individual conflicts replaces yarn file with tg version, bumping us down to 2200-ish Down to 2000 individual conflicts 140 down mmm aaaaaaaaaaaaaaaaaaa not yt 575 soon 900 individual conflicts 600 individual conflicts, 121 file conflicts im not okay 160 across 19 files 29 in 4 files 0 conflicts, compiletime fix time some minor incap stuff missed ticks weird dupe definition stuff missed ticks 2 incap fixes undefs and pie fix Radio update and some extra minor stuff returns a single override no more dupe definitions, 175 compiletime errors Unticked file fix sound and emote stuff honk and more radio stuff
208 lines
9.7 KiB
Plaintext
208 lines
9.7 KiB
Plaintext
/// Queues and manages JPS pathfinding steps
|
|
SUBSYSTEM_DEF(pathfinder)
|
|
name = "Pathfinder"
|
|
init_order = INIT_ORDER_PATH
|
|
priority = FIRE_PRIORITY_PATHFINDING
|
|
wait = 0.5
|
|
/// List of pathfind datums we are currently trying to process
|
|
var/list/datum/pathfind/active_pathing = list()
|
|
/// List of pathfind datums being ACTIVELY processed. exists to make subsystem stats readable
|
|
var/list/datum/pathfind/currentrun = list()
|
|
/// List of uncheccked source_to_map entries
|
|
var/list/currentmaps = list()
|
|
/// Assoc list of target turf -> list(/datum/path_map) centered on the turf
|
|
var/list/source_to_maps = list()
|
|
var/static/space_type_cache
|
|
|
|
/datum/controller/subsystem/pathfinder/Initialize()
|
|
space_type_cache = typecacheof(/turf/open/space)
|
|
return SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/pathfinder/stat_entry(msg)
|
|
msg = "P:[length(active_pathing)]"
|
|
return ..()
|
|
|
|
// This is another one of those subsystems (hey lighting) in which one "Run" means fully processing a queue
|
|
// We'll use a copy for this just to be nice to people reading the mc panel
|
|
/datum/controller/subsystem/pathfinder/fire(resumed)
|
|
if(!resumed)
|
|
src.currentrun = active_pathing.Copy()
|
|
src.currentmaps = deep_copy_list(source_to_maps)
|
|
|
|
// Dies of sonic speed from caching datum var reads
|
|
var/list/currentrun = src.currentrun
|
|
while(length(currentrun))
|
|
var/datum/pathfind/path = currentrun[length(currentrun)]
|
|
if(!path.search_step()) // Something's wrong
|
|
path.early_exit()
|
|
currentrun.len--
|
|
continue
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
path.finished()
|
|
// Next please
|
|
currentrun.len--
|
|
|
|
// Go over our existing pathmaps, clear out the ones we aren't using
|
|
var/list/currentmaps = src.currentmaps
|
|
var/oldest_time = world.time - MAP_REUSE_SLOWEST
|
|
while(length(currentmaps))
|
|
var/turf/source = currentmaps[length(currentmaps)]
|
|
var/list/datum/path_map/owned_maps = currentmaps[source]
|
|
for(var/datum/path_map/map as anything in owned_maps)
|
|
if(map.creation_time < oldest_time && !map.building)
|
|
source_to_maps[source] -= map
|
|
owned_maps.len--
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
if(!length(source_to_maps[source]))
|
|
source_to_maps -= source
|
|
|
|
currentmaps.len--
|
|
|
|
/// Initiates a pathfind. Returns true if we're good, FALSE if something's failed
|
|
/datum/controller/subsystem/pathfinder/proc/pathfind(atom/movable/caller, atom/end, max_distance = 30, mintargetdist, access = list(), simulated_only = TRUE, turf/exclude, skip_first = TRUE, diagonal_handling = DIAGONAL_REMOVE_CLUNKY, list/datum/callback/on_finish)
|
|
var/datum/pathfind/jps/path = new()
|
|
path.setup(caller, access, max_distance, simulated_only, exclude, on_finish, end, mintargetdist, skip_first, diagonal_handling)
|
|
if(path.start())
|
|
active_pathing += path
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Initiates a swarmed pathfind. Returns TRUE if we're good, FALSE if something's failed
|
|
/// If a valid pathmap exists for the TARGET turf we'll use that, otherwise we have to build a new one
|
|
/datum/controller/subsystem/pathfinder/proc/swarmed_pathfind(atom/movable/caller, atom/end, max_distance = 30, mintargetdist = 0, age = MAP_REUSE_INSTANT, access = list(), simulated_only = TRUE, turf/exclude, skip_first = TRUE, list/datum/callback/on_finish)
|
|
var/turf/target = get_turf(end)
|
|
var/datum/can_pass_info/pass_info = new(caller, access)
|
|
// If there's a map we can use already, use it
|
|
var/datum/path_map/valid_map = get_valid_map(pass_info, target, simulated_only, exclude, age, include_building = TRUE)
|
|
if(valid_map && valid_map.expand(max_distance))
|
|
path_map_passalong(on_finish, get_turf(caller), mintargetdist, skip_first, valid_map)
|
|
return TRUE
|
|
|
|
// Otherwise we're gonna make a new one, and turn it into a path for the callbacks passed into us
|
|
var/list/datum/callback/pass_in = list()
|
|
pass_in += CALLBACK(GLOBAL_PROC, /proc/path_map_passalong, on_finish, get_turf(caller), mintargetdist, skip_first)
|
|
// And to allow subsequent calls to reuse the same map, we'll put a placeholder in the cache, and fill it up when the pathing finishes
|
|
var/datum/path_map/empty = new()
|
|
empty.pass_info = new(caller, access)
|
|
empty.start = target
|
|
empty.pass_space = simulated_only
|
|
empty.avoid = exclude
|
|
empty.building = TRUE
|
|
path_map_cache(target, empty)
|
|
pass_in += CALLBACK(src, PROC_REF(path_map_fill), target, empty)
|
|
if(!SSpathfinder.can_pass_build_map(pass_info, target, max_distance, simulated_only, exclude, pass_in))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/// We generate a path for the passed in callbacks, and then pipe it over
|
|
/proc/path_map_passalong(list/datum/callback/return_callbacks, turf/target, mintargetdist = 0, skip_first = TRUE, datum/path_map/hand_back)
|
|
var/list/requested_path
|
|
if(istype(hand_back, /datum/path_map))
|
|
requested_path = hand_back.get_path_from(target, skip_first, mintargetdist)
|
|
for(var/datum/callback/return_callback as anything in return_callbacks)
|
|
return_callback.Invoke(requested_path)
|
|
|
|
/// Caches the passed in path_map, allowing for reuse in future
|
|
/datum/controller/subsystem/pathfinder/proc/path_map_cache(turf/target, datum/path_map/hand_back)
|
|
// Cache our path_map
|
|
if(!target || !hand_back)
|
|
return
|
|
source_to_maps[target] += list(hand_back)
|
|
|
|
/datum/controller/subsystem/pathfinder/proc/path_map_fill(turf/target, datum/path_map/fill_into, datum/path_map/hand_back)
|
|
fill_into.building = FALSE
|
|
if(!fill_into.compare_against(hand_back))
|
|
source_to_maps[target] -= fill_into
|
|
return
|
|
fill_into.copy_from(hand_back)
|
|
fill_into.creation_time = hand_back.creation_time
|
|
// If we aren't in the source list anymore don't go trying to clear it out yeah?
|
|
if(!source_to_maps[target] || !(fill_into in source_to_maps[target]))
|
|
return
|
|
// Let's remove anything we're better than
|
|
for(var/datum/path_map/same_target as anything in source_to_maps[target])
|
|
if(fill_into == same_target || !same_target.compare_against(hand_back))
|
|
continue
|
|
// If it's still being made it'll be fresher then us
|
|
if(same_target.building)
|
|
continue
|
|
// We assume that we are fresher, and that's all we care about
|
|
// If it's being expanded it'll get updated when that finishes, then clear when all the refs drop
|
|
source_to_maps[target] -= same_target
|
|
|
|
/// Initiates a SSSP run. Returns true if we're good, FALSE if something's failed
|
|
/datum/controller/subsystem/pathfinder/proc/build_map(atom/movable/caller, turf/source, max_distance = 30, access = list(), simulated_only = TRUE, turf/exclude, list/datum/callback/on_finish)
|
|
var/datum/pathfind/sssp/path = new()
|
|
path.setup(caller, access, source, max_distance, simulated_only, exclude, on_finish)
|
|
if(path.start())
|
|
active_pathing += path
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Initiates a SSSP run from a pass_info datum. Returns true if we're good, FALSE if something's failed
|
|
/datum/controller/subsystem/pathfinder/proc/can_pass_build_map(datum/can_pass_info/pass_info, turf/source, max_distance = 30, simulated_only = TRUE, turf/exclude, list/datum/callback/on_finish)
|
|
var/datum/pathfind/sssp/path = new()
|
|
path.setup_from_canpass(pass_info, source, max_distance, simulated_only, exclude, on_finish)
|
|
if(path.start())
|
|
active_pathing += path
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Begins to handle a pathfinding run based off the input /datum/pathfind datum
|
|
/// You should not use this, it exists to allow for shenanigans. You do not know how to do shenanigans
|
|
/datum/controller/subsystem/pathfinder/proc/run_pathfind(datum/pathfind/run)
|
|
active_pathing += run
|
|
return TRUE
|
|
|
|
/// Takes a set of pathfind info, returns the first valid pathmap that would work if one exists
|
|
/// Optionally takes a max age to accept (defaults to 0 seconds) and a minimum acceptable range
|
|
/// If include_building is true and we can only find a building path, we'll use that instead. tho we will wait for it to finish first
|
|
/datum/controller/subsystem/pathfinder/proc/get_valid_map(datum/can_pass_info/pass_info, turf/target, simulated_only = TRUE, turf/exclude, age = MAP_REUSE_INSTANT, min_range = -INFINITY, include_building = FALSE)
|
|
// Walk all the maps that match our caller's turf OR our target's
|
|
// Then hold onto em. If their cache time is short we can reuse/expand them, if not we'll have to make a new one
|
|
var/oldest_time = world.time - age
|
|
/// Backup return value used if no finished pathmaps are found
|
|
var/datum/path_map/constructing
|
|
for(var/datum/path_map/shared_source as anything in source_to_maps[target])
|
|
if(!shared_source.compare_against_args(pass_info, target, simulated_only, exclude))
|
|
continue
|
|
var/max_dist = 0
|
|
if(shared_source.distances.len)
|
|
max_dist = shared_source.distances[shared_source.distances.len]
|
|
if(max_dist < min_range)
|
|
continue
|
|
if(oldest_time > shared_source.creation_time && !shared_source.building)
|
|
continue
|
|
if(shared_source.building)
|
|
if(include_building)
|
|
constructing = constructing || shared_source
|
|
continue
|
|
|
|
return shared_source
|
|
if(constructing)
|
|
UNTIL(constructing.building == FALSE)
|
|
return constructing
|
|
return null
|
|
|
|
/// Takes a set of pathfind info, returns all valid pathmaps that would work
|
|
/// Takes an optional minimum range arg
|
|
/datum/controller/subsystem/pathfinder/proc/get_valid_maps(datum/can_pass_info/pass_info, turf/target, simulated_only = TRUE, turf/exclude, age = MAP_REUSE_INSTANT, min_range = -INFINITY, include_building = FALSE)
|
|
// Walk all the maps that match our caller's turf OR our target's
|
|
// Then hold onto em. If their cache time is short we can reuse/expand them, if not we'll have to make a new one
|
|
var/list/valid_maps = list()
|
|
var/oldest_time = world.time - age
|
|
for(var/datum/path_map/shared_source as anything in source_to_maps[target])
|
|
if(shared_source.compare_against_args(pass_info, target, simulated_only, exclude))
|
|
continue
|
|
var/max_dist = shared_source.distances[shared_source.distances.len]
|
|
if(max_dist < min_range)
|
|
continue
|
|
if(oldest_time > shared_source.creation_time)
|
|
continue
|
|
if(!include_building && shared_source.building)
|
|
continue
|
|
valid_maps += shared_source
|
|
return valid_maps
|