mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Co-authored-by: Changelogs <action@github.com> Co-authored-by: Heroman3003 <31296024+Heroman3003@users.noreply.github.com> Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: Kashargul <KashL@t-online.de>
136 lines
6.0 KiB
Plaintext
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)
|