Small improvments.

This commit is contained in:
Keleborn 2026-04-17 12:24:33 -07:00
parent 233790a430
commit 8cf684a141
5 changed files with 47 additions and 34 deletions

View File

@ -6,10 +6,10 @@
#include "CheckValuesAction.h" #include "CheckValuesAction.h"
#include "Event.h" #include "Event.h"
#include "ObjectGuid.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "PlayerbotAI.h" #include "PlayerbotAI.h"
#include "TravelNode.h"
#include "AiObjectContext.h" #include "AiObjectContext.h"
CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values") {} CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values") {}
@ -21,11 +21,6 @@ bool CheckValuesAction::Execute(Event /*event*/)
botAI->Ping(bot->GetPositionX(), bot->GetPositionY()); botAI->Ping(bot->GetPositionX(), bot->GetPositionY());
} }
if (botAI->HasStrategy("map", BOT_STATE_NON_COMBAT) || botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT))
{
TravelNodeMap::instance().manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT));
}
GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets"); GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets");
GuidVector all_targets = *context->GetValue<GuidVector>("all targets"); GuidVector all_targets = *context->GetValue<GuidVector>("all targets");
GuidVector npcs = *context->GetValue<GuidVector>("nearest npcs"); GuidVector npcs = *context->GetValue<GuidVector>("nearest npcs");

View File

@ -76,7 +76,7 @@ bool DebugAction::Execute(Event event)
return false; return false;
std::vector<WorldPosition> beginPath, endPath; std::vector<WorldPosition> beginPath, endPath;
TravelNodeRoute route = TravelNodeMap::instance().GetNearestNodes(botPos, *points.front(), beginPath, bot); TravelNodeRoute route = TravelNodeMap::instance().FindRouteNearestNodes(botPos, *points.front(), beginPath, bot);
std::ostringstream out; std::ostringstream out;
out << "Traveling to " << dest->getTitle() << ": "; out << "Traveling to " << dest->getTitle() << ": ";

View File

@ -2997,6 +2997,14 @@ bool MovementAction::CheckSplineProgress(TravelPlan& state)
if (!state.splineActive) if (!state.splineActive)
return false; return false;
// walkPoints may have been cleared by a map transfer or external reset
// while the spline was still flagged active; bail out safely.
if (state.walkPoints.empty())
{
state.splineActive = false;
return false;
}
if (bot->movespline->Finalized()) if (bot->movespline->Finalized())
{ {
G3D::Vector3 const& endPt = state.walkPoints.back(); G3D::Vector3 const& endPt = state.walkPoints.back();
@ -3009,7 +3017,7 @@ bool MovementAction::CheckSplineProgress(TravelPlan& state)
return true; // Arrived return true; // Arrived
} }
// If we havent arrived to destination, but are done moving then something interrupted it. // If we haven't arrived to destination, but are done moving then something interrupted it.
// Need to restart. Reset state // Need to restart. Reset state
state.splineActive = false; state.splineActive = false;
return false; return false;
@ -3226,7 +3234,7 @@ bool MovementAction::ExecuteTravelPlan(TravelPlan& state)
if (dist > INTERACTION_DISTANCE) if (dist > INTERACTION_DISTANCE)
return MoveTo(src.point.GetMapId(), src.point.GetPositionX(), src.point.GetPositionY(), src.point.GetPositionZ()); return MoveTo(src.point.GetMapId(), src.point.GetPositionX(), src.point.GetPositionY(), src.point.GetPositionZ());
// At portal, but havent teleported though // At portal, but haven't teleported through
TeleportFallback(state, dst.point, "portal walk-through"); TeleportFallback(state, dst.point, "portal walk-through");
state.stepIdx += 2; state.stepIdx += 2;
return true; return true;
@ -3369,6 +3377,14 @@ bool MovementAction::ExecuteTravelPlan(TravelPlan& state)
state.stepIdx += 2; state.stepIdx += 2;
return true; return true;
} }
default:
{
LOG_ERROR("playerbots",
"[TravelPlan] Bot {} encountered unknown PathNodeType ({}); resetting plan",
bot->GetName(), static_cast<uint32>(pt.type));
state.Reset();
return false;
}
} }
return false; return false;
} }

View File

@ -115,25 +115,25 @@ float TravelNodePath::getCost(Player* bot, uint32 cGold)
if (getPathType() == TravelNodePathType::flightPath && pathObject) if (getPathType() == TravelNodePathType::flightPath && pathObject)
{ {
if (!bot->IsAlive()) if (!bot->IsAlive())
return -1; return -1.0f;
TaxiPathEntry const* taxiPath = sTaxiPathStore.LookupEntry(pathObject); TaxiPathEntry const* taxiPath = sTaxiPathStore.LookupEntry(pathObject);
if (!taxiPath) if (!taxiPath)
return -1; return -1.0f;
if (!bot->isTaxiCheater() && taxiPath->price > cGold) if (!bot->isTaxiCheater() && taxiPath->price > cGold)
return -1; return -1.0f;
if (!bot->isTaxiCheater() && !bot->m_taxi.IsTaximaskNodeKnown(taxiPath->to)) if (!bot->isTaxiCheater() && !bot->m_taxi.IsTaximaskNodeKnown(taxiPath->to))
return -1; return -1.0f;
TaxiNodesEntry const* startTaxiNode = sTaxiNodesStore.LookupEntry(taxiPath->from); TaxiNodesEntry const* startTaxiNode = sTaxiNodesStore.LookupEntry(taxiPath->from);
TaxiNodesEntry const* endTaxiNode = sTaxiNodesStore.LookupEntry(taxiPath->to); TaxiNodesEntry const* endTaxiNode = sTaxiNodesStore.LookupEntry(taxiPath->to);
if (!startTaxiNode || !endTaxiNode || if (!startTaxiNode || !endTaxiNode ||
!startTaxiNode->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0] || !startTaxiNode->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0] ||
!endTaxiNode->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0]) !endTaxiNode->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0])
return -1; return -1.0f;
} }
speed = bot->GetSpeed(MOVE_RUN); speed = bot->GetSpeed(MOVE_RUN);
@ -164,7 +164,7 @@ float TravelNodePath::getCost(Player* bot, uint32 cGold)
if (getPathType() == TravelNodePathType::flyingMount) if (getPathType() == TravelNodePathType::flyingMount)
{ {
if (!bot->IsAlive() || bot->GetLevel() < 70 || !bot->CanFly()) if (!bot->IsAlive() || bot->GetLevel() < 70 || !bot->CanFly())
return -1; return -1.0f;
float flySpeed = bot->GetSpeed(MOVE_FLIGHT); float flySpeed = bot->GetSpeed(MOVE_FLIGHT);
if (flySpeed < 1.0f) if (flySpeed < 1.0f)
@ -173,7 +173,7 @@ float TravelNodePath::getCost(Player* bot, uint32 cGold)
} }
} }
else if (getPathType() == TravelNodePathType::flightPath || getPathType() == TravelNodePathType::flyingMount) else if (getPathType() == TravelNodePathType::flightPath || getPathType() == TravelNodePathType::flyingMount)
return -1; return -1.0f;
if (getPathType() != TravelNodePathType::walk) if (getPathType() != TravelNodePathType::walk)
timeCost = extraCost * modifier; timeCost = extraCost * modifier;
@ -1097,7 +1097,12 @@ TravelNodeRoute TravelNodeMap::GetNodeRoute(TravelNode* start, TravelNode* goal,
while (!open.empty()) while (!open.empty())
{ {
if (++nodesExplored > MAX_A_STAR_EXPLORED) if (++nodesExplored > MAX_A_STAR_EXPLORED)
{
LOG_DEBUG("playerbots",
"[TravelNode A*] Exceeded MAX_A_STAR_EXPLORED ({}); truncating route from '{}' to '{}'",
MAX_A_STAR_EXPLORED, start->getName(), goal->getName());
return TravelNodeRoute(); return TravelNodeRoute();
}
std::pop_heap(open.begin(), open.end(), heapComp); std::pop_heap(open.begin(), open.end(), heapComp);
currentNode = open.back(); currentNode = open.back();
@ -1164,7 +1169,7 @@ TravelNodeRoute TravelNodeMap::GetNodeRoute(TravelNode* start, TravelNode* goal,
return TravelNodeRoute(); return TravelNodeRoute();
} }
TravelNodeRoute TravelNodeMap::GetNearestNodes(WorldPosition startPos, WorldPosition endPos, TravelNodeRoute TravelNodeMap::FindRouteNearestNodes(WorldPosition startPos, WorldPosition endPos,
std::vector<WorldPosition>& startPath, Player* bot) std::vector<WorldPosition>& startPath, Player* bot)
{ {
if (nodes.empty() || !bot) if (nodes.empty() || !bot)
@ -1375,14 +1380,6 @@ TravelNode* TravelNodeMap::addRandomExtNode(TravelNode* startNode)
return nullptr; return nullptr;
} }
void TravelNodeMap::manageNodes(Unit* bot, bool mapFull)
{
// Runtime node mutation disabled — the graph is fully built at startup via Init()
// and .generate. Taking a unique_lock here caused 100-250ms contention spikes for
// all bot threads holding shared_locks in TravelPlan.
// Node pruning/creation is still available via the .generate console command.
}
void TravelNodeMap::generateNpcNodes() void TravelNodeMap::generateNpcNodes()
{ {
std::unordered_map<uint32, std::pair<CreatureTemplate const*, WorldPosition>> bossMap; std::unordered_map<uint32, std::pair<CreatureTemplate const*, WorldPosition>> bossMap;
@ -1943,6 +1940,14 @@ void TravelNodeMap::generateAll()
void TravelNodeMap::Init() void TravelNodeMap::Init()
{ {
InitTaxiGraph();
if (!sPlayerbotAIConfig.enableTravelNodes)
{
LOG_INFO("playerbots", "TravelNodeMap: travel node system disabled via AiPlayerbot.EnableTravelNodes=0 — skipping node load/generate/index.");
return;
}
LoadNodeStore(); LoadNodeStore();
calcMapOffset(); calcMapOffset();
@ -1961,7 +1966,6 @@ void TravelNodeMap::Init()
BuildZoneIndex(); BuildZoneIndex();
PrecomputeReachability(); PrecomputeReachability();
InitTaxiGraph();
LOG_INFO("playerbots", "TravelNodeMap initialized: {} nodes, zone index and reachability built.", LOG_INFO("playerbots", "TravelNodeMap initialized: {} nodes, zone index and reachability built.",
nodes.size()); nodes.size());
} }

View File

@ -647,15 +647,13 @@ public:
TravelNodeRoute GetNodeRoute(TravelNode* start, TravelNode* goal, TravelNodeRoute GetNodeRoute(TravelNode* start, TravelNode* goal,
Player* bot); Player* bot);
// Find the nearest start/end nodes for two world positions // Picks the nearest start/end nodes for two world positions and runs A*
TravelNodeRoute GetNearestNodes(WorldPosition startPos, // over the node graph to return a full route between them.
TravelNodeRoute FindRouteNearestNodes(WorldPosition startPos,
WorldPosition endPos, WorldPosition endPos,
std::vector<WorldPosition>& startPath, std::vector<WorldPosition>& startPath,
Player* bot = nullptr); Player* bot = nullptr);
// Manage/update nodes
void manageNodes(Unit* bot, bool mapFull = false);
void setHasToGen() { hasToGen = true; } void setHasToGen() { hasToGen = true; }
void generateNpcNodes(); void generateNpcNodes();