mirror of
https://github.com/Skyrat-SS13/Skyrat-tg.git
synced 2026-08-26 14:28:52 +01:00
Experiment with replacing weakrefs in AI blackboard with deleting signals, ideally making it easier to work with and harder to cause hard deletes (#74791)
## About The Pull Request Replaces weakref usage in AI blackboards with deleting signals All blackboard var setting must go through setters rather than directly ## Why It's Good For The Game This both makes it a ton easier to develop AI for, and also makes it harder for hard deletes to sneak in, as has been seen with recent 515 prs showing hard deletes in AI blackboards (To quantify "making it easier to develop AI", I found multiple bugs in existing AI code due to the usage of weakrefs.) I'm looking for `@Jacquerel` `@tralezab` 's opinions on the matter, also maybe `@LemonInTheDark` if they're interested ## Changelog 🆑 Melbert refactor: Mob ai refactored once again /🆑
This commit is contained in:
@@ -4,22 +4,22 @@
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
//Hiding location is priority
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
return FALSE
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
if (!targetting_datum)
|
||||
return
|
||||
if(isnull(targetting_datum))
|
||||
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
|
||||
|
||||
//Hiding location is priority
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/mob/living/basic/basic_mob = controller.pawn
|
||||
//targetting datum will kill the action if not real anymore
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
|
||||
if(!targetting_datum.can_attack(basic_mob, target))
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
var/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
|
||||
|
||||
controller.blackboard[hiding_location_key] = hiding_target
|
||||
controller.set_blackboard_key(hiding_location_key, hiding_target)
|
||||
|
||||
if(hiding_target) //Slap it!
|
||||
basic_mob.melee_attack(hiding_target)
|
||||
@@ -39,7 +39,7 @@
|
||||
/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
if(!succeeded)
|
||||
controller.blackboard -= target_key
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/average_speed
|
||||
action_cooldown = 1 SECONDS
|
||||
@@ -55,9 +55,8 @@
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
@@ -65,8 +64,7 @@
|
||||
. = ..()
|
||||
var/mob/living/basic/basic_mob = controller.pawn
|
||||
//targetting datum will kill the action if not real anymore
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
|
||||
if(!targetting_datum.can_attack(basic_mob, target))
|
||||
@@ -80,7 +78,7 @@
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
|
||||
controller.blackboard[hiding_location_key] = WEAKREF(hiding_target)
|
||||
controller.set_blackboard_key(hiding_location_key, hiding_target)
|
||||
|
||||
if(shots>1)
|
||||
var/atom/burst_target = final_target
|
||||
@@ -94,4 +92,4 @@
|
||||
/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
if(!succeeded)
|
||||
controller.blackboard -= target_key
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -7,18 +7,16 @@
|
||||
|
||||
/datum/ai_behavior/pick_up_item/setup(datum/ai_controller/controller, target_key, storage_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/obj/item/target = weak_target?.resolve()
|
||||
var/obj/item/target = controller.blackboard[target_key]
|
||||
return isitem(target) && isturf(target.loc) && !target.anchored
|
||||
|
||||
/datum/ai_behavior/pick_up_item/perform(seconds_per_tick, datum/ai_controller/controller, target_key, storage_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/obj/item/target = weak_target?.resolve()
|
||||
if(!isturf(target?.loc)) // Someone picked it up or it got deleted
|
||||
var/obj/item/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target) || !isturf(target.loc)) // Someone picked it up or it got deleted
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
if(!in_range(controller.pawn, target)) // It teleported
|
||||
if(!controller.pawn.Adjacent(target)) // It teleported
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
pickup_item(controller, target, storage_key)
|
||||
@@ -26,22 +24,21 @@
|
||||
|
||||
/datum/ai_behavior/pick_up_item/finish_action(datum/ai_controller/controller, success, target_key, storage_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/datum/ai_behavior/pick_up_item/proc/pickup_item(datum/ai_controller/controller, obj/item/target, storage_key)
|
||||
var/atom/pawn = controller.pawn
|
||||
drop_existing_item(controller, storage_key)
|
||||
pawn.visible_message(span_notice("[pawn] picks up [target]."))
|
||||
target.forceMove(pawn)
|
||||
controller.blackboard[storage_key] = WEAKREF(target)
|
||||
controller.set_blackboard_key(storage_key, target)
|
||||
return TRUE
|
||||
|
||||
/datum/ai_behavior/pick_up_item/proc/drop_existing_item(datum/ai_controller/controller, storage_key)
|
||||
var/datum/weakref/carried_ref = controller.blackboard[storage_key]
|
||||
var/obj/item/carried_item = carried_ref?.resolve()
|
||||
var/obj/item/carried_item = controller.blackboard[storage_key]
|
||||
if(!carried_item)
|
||||
return
|
||||
controller.blackboard[storage_key] = null
|
||||
controller.clear_blackboard_key(storage_key)
|
||||
var/atom/pawn = controller.pawn
|
||||
if(carried_item.loc != pawn)
|
||||
return
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
var/run_distance = 9
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/setup(datum/ai_controller/controller, target_key, hiding_location_key)
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
if(!plot_path_away_from(controller, target))
|
||||
return FALSE
|
||||
@@ -17,9 +16,8 @@
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/escaped = !target || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/escaped = QDELETED(target) || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away
|
||||
if (escaped)
|
||||
finish_action(controller, succeeded = TRUE, target_key = target_key, hiding_location_key = hiding_location_key)
|
||||
return
|
||||
@@ -43,4 +41,4 @@
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/finish_action(datum/ai_controller/controller, succeeded, target_key, hiding_location_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -11,13 +11,12 @@
|
||||
var/step_distance = 3
|
||||
|
||||
/datum/ai_behavior/step_towards_turf/setup(datum/ai_controller/controller, turf_key)
|
||||
var/datum/weakref/weak_turf = controller.blackboard[turf_key]
|
||||
var/turf/target_turf = weak_turf?.resolve()
|
||||
if (!target_turf || target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
||||
var/turf/target_turf = controller.blackboard[turf_key]
|
||||
if (QDELETED(target_turf) || target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
||||
target_turf = find_destination_turf(args)
|
||||
if (!target_turf)
|
||||
return FALSE
|
||||
controller.blackboard[turf_key] = WEAKREF(target_turf)
|
||||
controller.set_blackboard_key(turf_key, target_turf)
|
||||
|
||||
if (target_turf.z != controller.pawn.z)
|
||||
return FALSE
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
|
||||
/datum/ai_behavior/stop_and_stare/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/movable/target = weak_target?.resolve()
|
||||
var/atom/movable/target = controller.blackboard[target_key]
|
||||
return ismovable(target) && isturf(target.loc) && ismob(controller.pawn)
|
||||
|
||||
/datum/ai_behavior/stop_and_stare/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
// i don't really like doing this but we wanna make sure that the cooldown is pertinent to what we need for this specific controller before we invoke parent
|
||||
action_cooldown = controller.blackboard[BB_STATIONARY_COOLDOWN]
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/movable/target = weak_target?.resolve()
|
||||
var/atom/movable/target = controller.blackboard[target_key]
|
||||
if(!ismovable(target) || !isturf(target.loc)) // just to make sure that nothing funky happened between setup and perform
|
||||
return
|
||||
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
/datum/ai_behavior/targeted_mob_ability
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
|
||||
var/datum/weakref/weak_ability = controller.blackboard[ability_key]
|
||||
var/datum/action/cooldown/ability = weak_ability?.resolve()
|
||||
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/mob/living/target = weak_target?.resolve()
|
||||
if(!ability || QDELETED(target))
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if(QDELETED(ability) || QDELETED(target))
|
||||
finish_action(controller, FALSE, ability_key, target_key)
|
||||
return
|
||||
var/mob/pawn = controller.pawn
|
||||
@@ -19,16 +16,15 @@
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
return
|
||||
if (!isliving(target))
|
||||
return
|
||||
var/mob/living/living_target = target
|
||||
if(living_target.stat >= UNCONSCIOUS)
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/**
|
||||
* # Try Mob Ability and plan execute
|
||||
@@ -38,7 +34,7 @@
|
||||
/datum/ai_behavior/targeted_mob_ability/and_plan_execute
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_plan_execute/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
controller.blackboard[BB_BASIC_MOB_EXECUTION_TARGET] = controller.blackboard[target_key]
|
||||
controller.set_blackboard_key(BB_BASIC_MOB_EXECUTION_TARGET, controller.blackboard[target_key])
|
||||
return ..()
|
||||
|
||||
/**
|
||||
@@ -49,4 +45,4 @@
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_clear_target/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
if(!targetting_datum)
|
||||
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
|
||||
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/current_target = weak_target?.resolve()
|
||||
var/atom/current_target = controller.blackboard[target_key]
|
||||
if (targetting_datum.can_attack(living_mob, current_target))
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
var/list/potential_targets = hearers(vision_range, controller.pawn) - living_mob //Remove self, so we don't suicide
|
||||
|
||||
for(var/HM in typecache_filter_list(range(vision_range, living_mob), hostile_machines)) //Can we see any hostile machines?
|
||||
@@ -42,12 +41,12 @@
|
||||
return
|
||||
|
||||
var/atom/target = pick_final_target(controller, filtered_targets)
|
||||
controller.blackboard[target_key] = WEAKREF(target)
|
||||
controller.set_blackboard_key(target_key, target)
|
||||
|
||||
var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, target)
|
||||
|
||||
if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially.
|
||||
controller.blackboard[hiding_location_key] = WEAKREF(potential_hiding_location)
|
||||
controller.set_blackboard_key(hiding_location_key, potential_hiding_location)
|
||||
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
|
||||
@@ -33,5 +33,5 @@
|
||||
/datum/ai_behavior/tipped_reaction/finish_action(datum/ai_controller/controller, succeeded, tipper_key, reacting_key)
|
||||
. = ..()
|
||||
//I'VE SAID MY PEACE...
|
||||
controller.blackboard[reacting_key] = FALSE
|
||||
controller.blackboard[tipper_key] = null
|
||||
controller.set_blackboard_key(reacting_key, FALSE)
|
||||
controller.clear_blackboard_key(tipper_key)
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
|
||||
/datum/ai_behavior/travel_towards/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(isnull(target))
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user