Skip to content

Commit

Permalink
[MIRROR] Fixes a bunch of AI related CI runtimes [MDB IGNORE] (#25552)
Browse files Browse the repository at this point in the history
* Fixes a bunch of AI related CI runtimes (#80202)

## About The Pull Request

<details><summary>A bunch of the numerous CI issues </summary>

![image](https://github.com/tgstation/tgstation/assets/13398309/70b0419e-0ac4-4a59-8acb-02511f8d6987)

![image](https://github.com/tgstation/tgstation/assets/13398309/4303923d-aaea-438f-9eb2-d27b510c7bc6)

</details>

You can view the full list of them here
https://github.com/Skyrat-SS13/Skyrat-tg/actions/runs/7148986054/job/19470671408.

What seems to be happening is, the `ai_controller` `fire()`s, and at
some point the the `pawn` var has become null from qdeletion. Many of
the `SelectBehaviors()` procs make use of that var, and then try to
access it without any safeties whatsoever.

I believe it is mainly happening because of long `do_after()`s and other
procs that sleep.

This PR just adds those safeties. I probably didn't get them all, but
this should fix the ones I have seen in CI. There may be a better
solution to cover all future cases of this but I will wait on feedback
to proceed. See below comments:

---

I don't know if you would rather this to always be checked at the
controller level instead (or in `able_to_plan()` perhaps?) but I could
do that if it's wanted. I wasn't sure if there were certain things that
depended on `SelectBehaviors()` running for cleanup so I opted against
that.

On that note, shouldn't we just be qdeleting the `ai_controller` when
the pawn gets qdeleted? Is that not already happening? And if not, is
there a reason for it? That would probably be the best way to handle
it...

## Why It's Good For The Game

I would like to stop seeing so many random CI failures, wouldn't you?

## Changelog

:cl:
fix: fixes some AI runtimes that were caused by the pawn becoming null
/:cl:

* Fixes a bunch of AI related CI runtimes

---------

Co-authored-by: Bloop <[email protected]>
  • Loading branch information
2 people authored and FFMirrorBot committed Dec 11, 2023
1 parent 5a91c20 commit 85916ef
Show file tree
Hide file tree
Showing 10 changed files with 31 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/datum/ai_planning_subtree/opportunistic_ventcrawler

/datum/ai_planning_subtree/opportunistic_ventcrawler/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if(HAS_TRAIT(controller.pawn, TRAIT_MOVE_VENTCRAWLING))
if(QDELETED(controller.pawn) || HAS_TRAIT(controller.pawn, TRAIT_MOVE_VENTCRAWLING))
return SUBTREE_RETURN_FINISH_PLANNING // hold on let me cook

var/obj/machinery/atmospherics/components/unary/vent_pump/target = controller.blackboard[BB_ENTRY_VENT_TARGET]
Expand Down
2 changes: 2 additions & 0 deletions code/datums/ai/generic/generic_subtrees.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
*/
/datum/ai_planning_subtree/generic_resist/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(QDELETED(living_pawn))
return

if(SHOULD_RESIST(living_pawn) && SPT_PROB(RESIST_SUBTREE_PROB, seconds_per_tick))
controller.queue_behavior(/datum/ai_behavior/resist) //BRO IM ON FUCKING FIRE BRO
Expand Down
2 changes: 1 addition & 1 deletion code/datums/ai/hunting_behavior/hunting_behaviors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
return
var/mob/living/living_pawn = controller.pawn
// We can't hunt if we're indisposed
if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED) || living_pawn.stat != CONSCIOUS)
if(QDELETED(living_pawn) || HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED) || living_pawn.stat != CONSCIOUS)
return

var/atom/hunted = controller.blackboard[target_key]
Expand Down
2 changes: 2 additions & 0 deletions code/datums/ai/monkey/monkey_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ have ways of interacting with a specific mob and control it.

/datum/ai_controller/monkey/proc/set_trip_mode(mode = TRUE)
var/mob/living/carbon/regressed_monkey = pawn
if(QDELETED(regressed_monkey))
return
var/brain = regressed_monkey.get_organ_slot(ORGAN_SLOT_BRAIN)
if(istype(brain, /obj/item/organ/internal/brain/primate)) // In case we are a monkey AI in a human brain by who was previously controlled by a client but it now not by some marvel
var/obj/item/organ/internal/brain/primate/monkeybrain = brain
Expand Down
3 changes: 3 additions & 0 deletions code/datums/ai/monkey/monkey_subtrees.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
///monkey combat subtree.
/datum/ai_planning_subtree/monkey_combat/SelectBehaviors(datum/ai_controller/monkey/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(QDELETED(living_pawn))
return

var/list/enemies = controller.blackboard[BB_MONKEY_ENEMIES]

if((HAS_TRAIT(controller.pawn, TRAIT_PACIFISM)) || (!length(enemies) && !controller.blackboard[BB_MONKEY_AGGRESSIVE])) //Pacifist, or we have no enemies and we're not pissed
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/basic/bots/bot_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@

/datum/ai_planning_subtree/find_patrol_beacon/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
if(!(bot_pawn.bot_mode_flags & BOT_MODE_AUTOPATROL) || bot_pawn.mode == BOT_SUMMON)
if(QDELETED(bot_pawn) || !(bot_pawn.bot_mode_flags & BOT_MODE_AUTOPATROL) || bot_pawn.mode == BOT_SUMMON)
return

if(controller.blackboard_key_exists(BB_BEACON_TARGET))
Expand Down Expand Up @@ -186,7 +186,7 @@
/datum/ai_planning_subtree/salute_authority/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
//we are criminals, dont salute the dirty pigs
if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
if(QDELETED(bot_pawn) || bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
return
if(controller.blackboard_key_exists(BB_SALUTE_TARGET))
controller.queue_behavior(/datum/ai_behavior/salute_authority, BB_SALUTE_TARGET, BB_SALUTE_MESSAGES)
Expand Down
8 changes: 4 additions & 4 deletions code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
/datum/ai_planning_subtree/pet_planning/cleanbot/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
//we are DONE listening to orders
if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
if(QDELETED(bot_pawn) || bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
return
return ..()

Expand All @@ -51,7 +51,7 @@
/datum/ai_planning_subtree/cleaning_subtree/SelectBehaviors(datum/ai_controller/basic_controller/bot/cleanbot/controller, seconds_per_tick)
var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn

if(LAZYLEN(bot_pawn.do_afters))
if(QDELETED(bot_pawn) || LAZYLEN(bot_pawn.do_afters))
return SUBTREE_RETURN_FINISH_PLANNING

if(controller.reachable_key(BB_CLEAN_TARGET, BOT_CLEAN_PATH_LIMIT))
Expand Down Expand Up @@ -85,7 +85,7 @@

/datum/ai_planning_subtree/acid_spray/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn
if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
if(QDELETED(bot_pawn) || !(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
return
if(controller.reachable_key(BB_ACID_SPRAY_TARGET, BOT_CLEAN_PATH_LIMIT))
controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_ACID_SPRAY_TARGET)
Expand Down Expand Up @@ -150,7 +150,7 @@

/datum/ai_planning_subtree/use_mob_ability/foam_area/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
if(QDELETED(bot_pawn) || !(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
return
return ..()

Expand Down
11 changes: 6 additions & 5 deletions code/modules/mob/living/basic/bots/medbot/medbot_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
/datum/ai_movement/jps/bot/medbot/allowed_to_move(datum/move_loop/source)
var/datum/ai_controller/controller = source.extra_info
var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn
if(bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE)
if(QDELETED(bot_pawn) || bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE)
return FALSE
return ..()

Expand All @@ -32,7 +32,7 @@

/datum/ai_planning_subtree/treat_wounded_target/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn
if(bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE)
if(QDELETED(bot_pawn) || bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE)
controller.clear_blackboard_key(BB_PATIENT_TARGET)
return
var/reach_distance = (bot_pawn.medical_mode_flags & MEDBOT_STATIONARY_MODE) ? 1 : BOT_PATIENT_PATH_LIMIT
Expand Down Expand Up @@ -98,7 +98,8 @@
if(patient.stat >= HARD_CRIT && prob(5))
var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY]
announcement?.announce(pick(controller.blackboard[BB_NEAR_DEATH_SPEECH]))
bot_pawn.melee_attack(patient)
if(!QDELETED(bot_pawn))
bot_pawn.melee_attack(patient)
finish_action(controller, TRUE, target_key)

// only clear the target if they get healed
Expand Down Expand Up @@ -126,7 +127,7 @@
/datum/ai_planning_subtree/handle_medbot_speech/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn
//we cant speak!
if(!(bot_pawn.medical_mode_flags & MEDBOT_SPEAK_MODE))
if(QDELETED(bot_pawn) || !(bot_pawn.medical_mode_flags & MEDBOT_SPEAK_MODE))
return

var/currently_tipped = bot_pawn.medical_mode_flags & MEDBOT_TIPPED_MODE
Expand Down Expand Up @@ -173,7 +174,7 @@

/datum/ai_planning_subtree/find_and_hunt_target/patients_in_crit/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/basic/bot/medbot/bot_pawn = controller.pawn
if(!(bot_pawn.medical_mode_flags & MEDBOT_DECLARE_CRIT))
if(QDELETED(bot_pawn) || !(bot_pawn.medical_mode_flags & MEDBOT_DECLARE_CRIT))
return
return ..()

Expand Down
6 changes: 5 additions & 1 deletion code/modules/mob/living/basic/pets/cat/cat_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

/datum/ai_planning_subtree/reside_in_home/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(QDELETED(living_pawn))
return

if(controller.blackboard_key_exists(BB_CAT_HOME))
controller.queue_behavior(/datum/ai_behavior/enter_cat_home, BB_CAT_HOME)
Expand Down Expand Up @@ -86,7 +88,7 @@

/datum/ai_planning_subtree/territorial_struggle/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(living_pawn.gender != MALE || !SPT_PROB(hostility_chance, seconds_per_tick))
if(QDELETED(living_pawn) || living_pawn.gender != MALE || !SPT_PROB(hostility_chance, seconds_per_tick))
return
if(controller.blackboard_key_exists(BB_TRESSPASSER_TARGET))
controller.queue_behavior(/datum/ai_behavior/territorial_struggle, BB_TRESSPASSER_TARGET, BB_HOSTILE_MEOWS)
Expand Down Expand Up @@ -165,6 +167,8 @@

/datum/ai_planning_subtree/find_and_hunt_target/hunt_mice/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(QDELETED(living_pawn))
return
var/list/items_we_carry = typecache_filter_list(living_pawn, controller.blackboard[BB_HUNTABLE_PREY])
if(length(items_we_carry))
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

/datum/ai_planning_subtree/perch_on_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
var/atom/buckled_too = living_pawn.buckled
if(QDELETED(living_pawn))
return

var/atom/buckled_to = living_pawn.buckled

//do we have a current target or is chance to unbuckle has passed? then unbuckle!
if(buckled_too)
if(buckled_to)
if((SPT_PROB(unperch_chance, seconds_per_tick) || controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)))
controller.queue_behavior(/datum/ai_behavior/unbuckle_mob)
return
Expand Down

0 comments on commit 85916ef

Please sign in to comment.