From 05db6f67b465953e05a40a78a97e42d73acf986d Mon Sep 17 00:00:00 2001 From: Yunfan Li <56597220+liyunfan1223@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:03:34 +0800 Subject: [PATCH] Add stuck fallback for rpg move far (#914) --- src/strategy/rpg/NewRpgAction.cpp | 58 ++++++++++++++++++++----------- src/strategy/rpg/NewRpgAction.h | 3 +- src/strategy/rpg/NewRpgStrategy.h | 9 ++++- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/strategy/rpg/NewRpgAction.cpp b/src/strategy/rpg/NewRpgAction.cpp index 30068c17..0f6697d7 100644 --- a/src/strategy/rpg/NewRpgAction.cpp +++ b/src/strategy/rpg/NewRpgAction.cpp @@ -38,10 +38,11 @@ bool NewRpgStatusUpdateAction::Execute(Event event) // if ((!info.lastNearNpc || info.lastNearNpc + setNpcInterval < getMSTime()) && roll <= 30) if (roll <= 30) { - info.lastNearNpc = getMSTime(); GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets"); if (!possibleTargets.empty()) { + info.Reset(); + info.lastNearNpc = getMSTime(); info.status = NewRpgStatus::NEAR_NPC; return true; } @@ -52,6 +53,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) WorldPosition pos = SelectRandomInnKeeperPos(); if (pos != WorldPosition() && bot->GetExactDist(pos) > 50.0f) { + info.Reset(); info.lastGoInnKeeper = getMSTime(); info.status = NewRpgStatus::GO_INNKEEPER; info.innKeeperPos = pos; @@ -64,6 +66,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) WorldPosition pos = SelectRandomGrindPos(); if (pos != WorldPosition()) { + info.Reset(); info.lastGoGrind = getMSTime(); info.status = NewRpgStatus::GO_GRIND; info.grindPos = pos; @@ -71,6 +74,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) } } // IDLE -> REST + info.Reset(); info.status = NewRpgStatus::REST; info.lastRest = getMSTime(); bot->SetStandState(UNIT_STAND_STATE_SIT); @@ -83,22 +87,12 @@ bool NewRpgStatusUpdateAction::Execute(Event event) // GO_GRIND -> NEAR_RANDOM if (bot->GetExactDist(originalPos) < 10.0f) { + info.Reset(); info.status = NewRpgStatus::NEAR_RANDOM; info.lastNearRandom = getMSTime(); info.grindPos = WorldPosition(); return true; } - // // just choose another grindPos - // if (!info.lastGoGrind || info.lastGoGrind + setGrindInterval < getMSTime()) - // { - // WorldPosition pos = SelectRandomGrindPos(); - // if (pos == WorldPosition()) - // break; - // info.status = NewRpgStatus::GO_GRIND; - // info.lastGoGrind = getMSTime(); - // info.grindPos = pos; - // return true; - // } break; } case NewRpgStatus::GO_INNKEEPER: @@ -108,6 +102,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) // GO_INNKEEPER -> NEAR_NPC if (bot->GetExactDist(originalPos) < 10.0f) { + info.Reset(); info.lastNearNpc = getMSTime(); info.status = NewRpgStatus::NEAR_NPC; info.innKeeperPos = WorldPosition(); @@ -120,6 +115,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) // NEAR_RANDOM -> IDLE if (info.lastNearRandom + statusNearRandomDuration < getMSTime()) { + info.Reset(); info.status = NewRpgStatus::IDLE; return true; } @@ -129,6 +125,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) { if (info.lastNearNpc + statusNearNpcDuration < getMSTime()) { + info.Reset(); info.status = NewRpgStatus::IDLE; return true; } @@ -139,6 +136,7 @@ bool NewRpgStatusUpdateAction::Execute(Event event) // REST -> IDLE if (info.lastRest + statusRestDuration < getMSTime()) { + info.Reset(); info.status = NewRpgStatus::IDLE; return true; } @@ -173,7 +171,7 @@ WorldPosition NewRpgStatusUpdateAction::SelectRandomGrindPos() lo_prepared_locs.push_back(loc); } } - WorldPosition dest; + WorldPosition dest{}; if (urand(1, 100) <= 50 && !hi_prepared_locs.empty()) { uint32 idx = urand(0, hi_prepared_locs.size() - 1); @@ -211,7 +209,7 @@ WorldPosition NewRpgStatusUpdateAction::SelectRandomInnKeeperPos() prepared_locs.push_back(loc); } } - WorldPosition dest; + WorldPosition dest{}; if (!prepared_locs.empty()) { uint32 idx = urand(0, prepared_locs.size() - 1); @@ -225,6 +223,9 @@ WorldPosition NewRpgStatusUpdateAction::SelectRandomInnKeeperPos() bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest) { + if (dest == WorldPosition()) + return false; + float dis = bot->GetExactDist(dest); if (dis < pathFinderDis) { @@ -238,6 +239,27 @@ bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest) return false; } + // stuck check + float disToDest = bot->GetDistance(dest); + if (disToDest + 1.0f < botAI->rpgInfo.nearestMoveFarDis) + { + botAI->rpgInfo.nearestMoveFarDis = disToDest; + botAI->rpgInfo.stuckTs = getMSTime(); + botAI->rpgInfo.stuckAttempts = 0; + } + else if (++botAI->rpgInfo.stuckAttempts >= 10 && botAI->rpgInfo.stuckTs + stuckTime < getMSTime()) + { + // Unfortunately we've been stuck here for over 5 mins, fallback to teleporting directly to the destination + botAI->rpgInfo.stuckTs = getMSTime(); + botAI->rpgInfo.stuckAttempts = 0; + const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId()); + std::string zone_name = PlayerbotAI::GetLocalizedAreaName(entry); + LOG_DEBUG("playerbots", "[New Rpg] Teleport {} from ({},{},{},{}) to ({},{},{},{}) as it stuck when moving far - Zone: {} ({})", bot->GetName(), + bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId(), + dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.getMapId(), bot->GetZoneId(), zone_name); + return bot->TeleportTo(dest); + } + float minDelta = M_PI; const float x = bot->GetPositionX(); const float y = bot->GetPositionY(); @@ -254,12 +276,11 @@ bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest) float dx = x + cos(angle) * dis; float dy = y + sin(angle) * dis; float dz = z + 0.5f; - bot->UpdateAllowedPositionZ(dx, dy, dz); PathGenerator path(bot); path.CalculatePath(dx, dy, dz); PathType type = path.GetPathType(); - - bool canReach = type == PATHFIND_NORMAL; + uint32 typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY; + bool canReach = !(type & (~typeOk)); if (canReach && fabs(delta) <= minDelta) { @@ -275,9 +296,6 @@ bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest) { return MoveTo(bot->GetMapId(), rx, ry, rz, false, false, false, true); } - // don't fallback to direct move - // float angle = bot->GetAngle(&dest); - // return MoveTo(bot->GetMapId(), x + cos(angle) * pathFinderDis, y + sin(angle) * pathFinderDis, z); return false; } diff --git a/src/strategy/rpg/NewRpgAction.h b/src/strategy/rpg/NewRpgAction.h index 058822be..83cb604a 100644 --- a/src/strategy/rpg/NewRpgAction.h +++ b/src/strategy/rpg/NewRpgAction.h @@ -39,7 +39,8 @@ public: protected: // WorldPosition dest; - float pathFinderDis = 70.0f; // path finder + const float pathFinderDis = 70.0f; // path finder + const uint32 stuckTime = 5 * 60 * 1000; }; class NewRpgGoGrindAction : public NewRpgGoFarAwayPosAction diff --git a/src/strategy/rpg/NewRpgStrategy.h b/src/strategy/rpg/NewRpgStrategy.h index 36ddb67d..1c5a6423 100644 --- a/src/strategy/rpg/NewRpgStrategy.h +++ b/src/strategy/rpg/NewRpgStrategy.h @@ -43,7 +43,10 @@ struct NewRpgInfo uint32 lastNearRandom{0}; // NewRpgStatus::REST uint32 lastRest{0}; - + // MOVE_FAR + float nearestMoveFarDis{FLT_MAX}; + uint32 stuckTs{0}; + uint32 stuckAttempts{0}; std::string ToString() { std::stringstream out; @@ -82,6 +85,10 @@ struct NewRpgInfo } return out.str(); } + void Reset() + { + *this = NewRpgInfo(); + } }; class NewRpgStrategy : public Strategy