Files
CHOMPStation2/code/controllers/subsystems/pathfinder_ch.dm
2024-09-30 21:36:41 +02:00

136 lines
6.0 KiB
Plaintext

//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//
#define PATHFINDER_TIMEOUT 50
SUBSYSTEM_DEF(pathfinder)
name = "Pathfinder"
flags = SS_NO_INIT | SS_NO_FIRE
/// pathfinding mutex - most algorithms depend on this
/// multi "threading" in byond just adds overhead
/// from everything trying to re-queue their executions
/// for this reason, much like with maploading,
/// it's somewhat pointless to have more than one operation going
/// at a time
var/pathfinding_mutex = FALSE
/// pathfinding calls blocked
var/pathfinding_blocked = 0
/// pathfinding cycle - this is usable because of the mutex
/// this is used in place of a closed list in algorithms like JPS
/// to maximize performance.
var/tmp/pathfinding_cycle = 0
/**
* be aware that this emits a set of disjunct nodes
* use [jps_output_turfs()] to convert them into a proper turf path list.
*
* Please see [code/__HELPERS/pathfinding/jps.dm] for details on what JPS does/is.
*/
/datum/controller/subsystem/pathfinder/proc/get_path_jps(atom/movable/actor = GLOB.generic_pathfinding_actor, turf/goal, turf/start = get_turf(actor), target_distance = 1, max_path_length = 128)
var/datum/pathfinding/jps/instance = new(actor, start, goal, target_distance, max_path_length)
return run_pathfinding(instance)
/**
* Please see [code/__HELPERS/pathfinding/astar.dm] for details on what JPS does/is.
*/
/datum/controller/subsystem/pathfinder/proc/get_path_astar(atom/movable/actor = GLOB.generic_pathfinding_actor, turf/goal, turf/start = get_turf(actor), target_distance = 1, max_path_length = 128)
var/datum/pathfinding/astar/instance = new(actor, start, goal, target_distance, max_path_length)
return run_pathfinding(instance)
/datum/controller/subsystem/pathfinder/proc/default_ai_pathfinding(datum/ai_holder/holder, turf/goal, min_dist = 1, max_path = 128)
var/datum/pathfinding/astar/instance = new(holder.holder, get_turf(holder.holder), goal, min_dist, max_path * 2)
var/obj/item/card/id/potential_id = holder.holder.GetIdCard()
if(!isnull(potential_id))
instance.ss13_with_access = potential_id.access?.Copy()
return run_pathfinding(instance)
/datum/controller/subsystem/pathfinder/proc/default_circuit_pathfinding(obj/item/electronic_assembly/assembly, turf/goal, min_dist = 1, max_path = 128, var/list/access)
var/datum/pathfinding/jps/instance = new(assembly, get_turf(assembly), goal, min_dist, max_path)
instance.ss13_with_access = access.Copy()
return jps_output_turfs(run_pathfinding(instance))
/datum/controller/subsystem/pathfinder/proc/default_bot_pathfinding(mob/living/bot/bot, turf/goal, min_dist = 1, max_path = 128)
var/datum/pathfinding/jps/instance = new(bot, get_turf(bot), goal, min_dist, max_path)
instance.ss13_with_access = bot.botcard.access?.Copy()
return jps_output_turfs(run_pathfinding(instance))
/datum/controller/subsystem/pathfinder/proc/run_pathfinding(datum/pathfinding/instance)
var/started = world.time
++pathfinding_blocked
if(pathfinding_blocked < 10)
while(pathfinding_mutex)
stoplag(1)
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
return
else
while(pathfinding_mutex)
stoplag(3)
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
return
--pathfinding_blocked
pathfinding_mutex = TRUE
. = instance.search()
if(world.time > started + PATHFINDER_TIMEOUT)
stack_trace("pathfinder timeout; check debug logs.")
log_debug("pathfinder timeout of instance with debug variables [instance.debug_log_string()]")
pathfinding_mutex = FALSE
#undef PATHFINDER_TIMEOUT
/proc/astar_debug(turf/target)
if(isnull(target))
return
return SSpathfinder.get_path_astar(usr, target, get_turf(usr))
/proc/jps_debug(turf/target)
if(isnull(target))
return
return SSpathfinder.get_path_jps(usr, target, get_turf(usr))
/proc/old_astar_debug(turf/target)
if(isnull(target))
return
return graph_astar(get_turf(usr), target, TYPE_PROC_REF(/turf, CardinalTurfsWithAccess), TYPE_PROC_REF(/turf, Distance), 0, 128, 1)
/proc/old_jps_debug(turf/target)
var/turf/start = get_turf(usr)
var/atom/movable/delegate_for_tg = new(start)
var/datum/tg_jps_pathfind/tg_instance = new(delegate_for_tg, target, null, 128, 1, FALSE, null)
return tg_instance.search()
/proc/pathfinding_run_all(turf/start = get_turf(usr), turf/goal)
var/pass_silicons_astar = SSpathfinder.get_path_astar(goal = goal, start = start, target_distance = 1, max_path_length = 256)
var/pass_silicons_jps = SSpathfinder.get_path_jps(goal = goal, start = start, target_distance = 1, max_path_length = 256)
// old astar has been cut because it's such horrible code it's not worth benchmarking against the other 3.
// var/pass_old_astar = graph_astar(
// start,
// goal,
// TYPE_PROC_REF(/turf, CardinalTurfsWithAccess),
// TYPE_PROC_REF(/turf, Distance),
// 0,
// 128,
// 1,
// )
var/atom/movable/delegate_for_tg = new(start)
var/datum/tg_jps_pathfind/tg_instance = new(delegate_for_tg, goal, null, 256, 1, FALSE, null)
var/pass_tg_jps = tg_instance.search()
pass_silicons_astar = !!length(pass_silicons_astar)
pass_silicons_jps = !!length(pass_silicons_jps)
// pass_old_astar = !!length(pass_old_astar)
pass_tg_jps = !!length(pass_tg_jps)
if(pass_silicons_astar != pass_silicons_jps || pass_silicons_jps != pass_tg_jps)
log_and_message_admins("turf pair [COORD(start)], [COORD(goal)] mismatch silicons-astar [pass_silicons_astar] silicons-jps [pass_silicons_jps] tg-jps [pass_tg_jps]")
else
log_and_message_admins("turf pair [COORD(start)], [COORD(goal)] succeeded")
/proc/pathfinding_run_benchmark(times = 1000, turf/source = get_turf(usr))
var/list/turf/nearby = RANGE_TURFS(100, source)
for(var/i in 1 to min(times, 10000))
var/turf/picked = pick(nearby)
pathfinding_run_all(source, picked)