From 9c00831f15821273adee4870b692443feddfb09f Mon Sep 17 00:00:00 2001 From: mand1nga Date: Wed, 20 Apr 2011 04:34:23 -0300 Subject: [PATCH] Added a better handling of stuck bots. Walkability is checked for every potential goal, and this check is spread among many frames. Also bots get unstuck one at a time, preventing server lag. --- qcsrc/server/bot/bot.qc | 6 ++ qcsrc/server/bot/bot.qh | 1 + qcsrc/server/bot/navigation.qc | 111 ++++++++++++++++++++++++++++----- qcsrc/server/bot/navigation.qh | 7 +++ 4 files changed, 108 insertions(+), 17 deletions(-) diff --git a/qcsrc/server/bot/bot.qc b/qcsrc/server/bot/bot.qc index 581e3f0c7..5c70af58c 100644 --- a/qcsrc/server/bot/bot.qc +++ b/qcsrc/server/bot/bot.qc @@ -99,6 +99,10 @@ void bot_think() } } + // + if(self.aistatus & AI_STATUS_STUCK) + navigation_unstuck(); + // now call the current bot AI (havocbot for example) self.bot_ai(); }; @@ -374,6 +378,8 @@ void bot_clientdisconnect() self.playermodel_freeme = string_null; self.playerskin_freeme = string_null; remove(self.bot_cmd_current); + if(navigation_wander_owner==self) + navigation_wander_owner = world; } void bot_clientconnect() diff --git a/qcsrc/server/bot/bot.qh b/qcsrc/server/bot/bot.qh index 9e6d447e6..b4556bb76 100644 --- a/qcsrc/server/bot/bot.qh +++ b/qcsrc/server/bot/bot.qh @@ -13,6 +13,7 @@ float AI_STATUS_WAYPOINT_PERSONAL_GOING = 128; // Going to a personal waypoint float AI_STATUS_WAYPOINT_PERSONAL_REACHED = 256; // Personal waypoint reached float AI_STATUS_JETPACK_FLYING = 512; float AI_STATUS_JETPACK_LANDING = 1024; +float AI_STATUS_STUCK = 2048; // bot cannot reach any useful goal .float isbot; // true if this client is actually a bot .float aistatus; diff --git a/qcsrc/server/bot/navigation.qc b/qcsrc/server/bot/navigation.qc index e460bdc57..e39c5408d 100644 --- a/qcsrc/server/bot/navigation.qc +++ b/qcsrc/server/bot/navigation.qc @@ -890,6 +890,9 @@ void navigation_poptouchedgoals() // begin a goal selection session (queries spawnfunc_waypoint network) void navigation_goalrating_start() { + if(self.aistatus & AI_STATUS_STUCK) + return; + self.navigation_jetpack_goal = world; navigation_bestrating = -1; self.navigation_hasgoals = FALSE; @@ -901,31 +904,21 @@ void navigation_goalrating_start() // ends a goal selection session (updates goal stack to the best goal) void navigation_goalrating_end() { + if(self.aistatus & AI_STATUS_STUCK) + return; + navigation_routetogoal(navigation_bestgoal, self.origin); // dprint("best goal ", self.goalcurrent.classname , "\n"); - // Hack: if it can't walk to any goal just move blindly to the first visible waypoint + // If the bot got stuck then try to reach the farthest waypoint if not (self.navigation_hasgoals) if (autocvar_bot_wander_enable) { - if not(autocvar_g_campaign) - dprint(self.netname, " can't walk to any goal, going to a near waypoint\n"); - - entity head; - - RandomSelection_Init(); - head = findradius(self.origin,1000); - while(head) + if not(self.aistatus & AI_STATUS_STUCK) { - if(head.classname=="waypoint") - if(!(head.wpflags & WAYPOINTFLAG_GENERATED)) - if(vlen(self.origin-head.origin)>100) - if(checkpvs(self.view_ofs,head)) - RandomSelection_Add(head, 0, string_null, 1 + (vlen(self.origin-head.origin)<500), 0); - head = head.chain; + dprint(self.netname, " cannot walk to any goal\n"); + self.aistatus |= AI_STATUS_STUCK; } - if(RandomSelection_chosen_ent) - navigation_routetogoal(RandomSelection_chosen_ent, self.origin); self.navigation_hasgoals = FALSE; // Reset this value } @@ -968,6 +961,90 @@ void botframe_updatedangerousobjects(float maxupdate) } }; +void navigation_unstuck() +{ + if not(navigation_wander_owner) + { + dprint(self.netname, " taking over the waypoints queue\n"); + navigation_wander_owner = self; + navigation_wander_bestgoal = world; + navigation_wander_bestgoalrating = 0; + } + + if(navigation_wander_owner!=self) + return; + + if (navigation_wander_goal) + { + // evaluate the next goal on the queue + float d = vlen(self.origin - navigation_wander_goal.origin); + dprint(self.netname, " evaluating ", navigation_wander_goal.classname, " with distance ", ftos(d), "\n"); + if(tracewalk(navigation_wander_goal, self.origin, PL_MIN, PL_MAX, navigation_wander_goal.origin, bot_navigation_movemode)) + { + if( d > navigation_wander_bestgoalrating) + { + navigation_wander_bestgoalrating = d; + navigation_wander_bestgoal = navigation_wander_goal; + } + } + navigation_wander_goal = navigation_wander_goal.navigation_wander_nextgoal; + + if not(navigation_wander_goal) + { + if (navigation_wander_bestgoal) + { + navigation_routetogoal(navigation_wander_bestgoal, self.origin); + self.bot_strategytime = time + autocvar_bot_ai_strategyinterval; + self.aistatus &~= AI_STATUS_STUCK; + } + else + { + dprint(self.netname, " got BADLY stuck, giving up.\n"); + } + + navigation_wander_owner = world; + } + } + else + { + // build a new queue + dprint(self.netname, " building a new wayoints queue\n"); + + entity first, head, prev; + head = findradius(self.origin, 1000); + + while(head) + { + if(head.classname=="waypoint") + if(!(head.wpflags & WAYPOINTFLAG_GENERATED)) + if(vlen(self.origin-head.origin)>100) + { + if (first==world) + { + first = head; + navigation_wander_goal = head; + } + else + { + prev = navigation_wander_goal; + navigation_wander_goal = head; + prev.navigation_wander_nextgoal = head; + navigation_wander_goal.navigation_wander_nextgoal = world; + } + } + + head = head.chain; + } + + if (first) + navigation_wander_goal = first; + else + { + dprint(self.netname, " got BADLY stuck, giving up.\n"); + } + } +} + // Support for debugging tracewalk visually void debugresetnodes() diff --git a/qcsrc/server/bot/navigation.qh b/qcsrc/server/bot/navigation.qh index 06bbb85c3..6355ef700 100644 --- a/qcsrc/server/bot/navigation.qh +++ b/qcsrc/server/bot/navigation.qh @@ -35,6 +35,12 @@ float DEBUG_NODE_WARNING = 2; float DEBUG_NODE_FAIL = 3; vector debuglastnode; +entity navigation_wander_owner; // Owner of the temporary list of goals +entity navigation_wander_goal; // Head of the temporary list of goals +.entity navigation_wander_nextgoal; +entity navigation_wander_bestgoal; +float navigation_wander_bestgoalrating; + /* * Functions */ @@ -60,6 +66,7 @@ void navigation_routerating(entity e, float f, float rangebias); void navigation_poptouchedgoals(); void navigation_goalrating_start(); void navigation_goalrating_end(); +void navigation_unstuck(); void botframe_updatedangerousobjects(float maxupdate); -- 2.39.2