added visible gryphon when bots using taxi-gryphon
This commit is contained in:
1 parent
24fb292cee
commit
93c3df1c95
5 files changed
+339
-2
No files matched your search
@@ -812,7 +812,39 @@ bool ClientlessActionExecutorMgr::StartRouteStep(
|
||||
sClientlessTravelMgr->CancelTravel(characterGuid);
|
||||
record.EdgePath.clear();
|
||||
|
||||
if (!player->ActivateTaxiPathTo(taxiPathId))
|
||||
// AdventureBots are performative world actors, not simulated
|
||||
// participants in the player economy. Give the normal Trinity taxi
|
||||
// code enough temporary money to pass its fare check, then restore the
|
||||
// bot's original balance immediately after the flight has been started.
|
||||
//
|
||||
// Use a generous temporary balance rather than taxiCost directly:
|
||||
// ActivateTaxiPathTo() may internally calculate a different total when
|
||||
// a path contains multiple legs.
|
||||
uint64 const originalMoney = player->GetMoney();
|
||||
constexpr uint64 TemporaryTaxiMoney = 1000000000ULL;
|
||||
|
||||
if (originalMoney < TemporaryTaxiMoney)
|
||||
player->SetMoney(TemporaryTaxiMoney);
|
||||
|
||||
// Clientless taxi movement runs server-side, but observers may
|
||||
// otherwise see the bot flying without a visible taxi mount. Resolve
|
||||
// the proper faction/node-specific taxi mount and apply it explicitly
|
||||
// before starting the normal Trinity taxi flight.
|
||||
uint32 const taxiMountDisplayId =
|
||||
sObjectMgr->GetTaxiMountDisplayId(
|
||||
sourceTaxiNodeId,
|
||||
player->GetTeam(),
|
||||
true);
|
||||
|
||||
if (taxiMountDisplayId && !player->IsMounted())
|
||||
player->Mount(taxiMountDisplayId);
|
||||
|
||||
bool const taxiStarted = player->ActivateTaxiPathTo(taxiPathId);
|
||||
|
||||
if (player->GetMoney() != originalMoney)
|
||||
player->SetMoney(originalMoney);
|
||||
|
||||
if (!taxiStarted)
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
#include "Log.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr float ARRIVAL_DISTANCE = 0.5f;
|
||||
@@ -35,6 +39,98 @@ char const* ClientlessTravelMgr::StateName(ClientlessTravelState state)
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool ClientlessTravelMgr::AnalyzePath(
|
||||
Player* player,
|
||||
Position const& target,
|
||||
ClientlessPathDiagnostics& diagnostics) const
|
||||
{
|
||||
diagnostics = {};
|
||||
|
||||
if (!player || !player->IsInWorld())
|
||||
{
|
||||
diagnostics.Reason = "player-not-in-world";
|
||||
return false;
|
||||
}
|
||||
|
||||
float const sx = player->GetPositionX();
|
||||
float const sy = player->GetPositionY();
|
||||
float const sz = player->GetPositionZ();
|
||||
float const tx = target.GetPositionX();
|
||||
float const ty = target.GetPositionY();
|
||||
float const tz = target.GetPositionZ();
|
||||
|
||||
float const ddx = tx - sx;
|
||||
float const ddy = ty - sy;
|
||||
float const ddz = tz - sz;
|
||||
diagnostics.DirectDistance = std::sqrt(ddx * ddx + ddy * ddy + ddz * ddz);
|
||||
|
||||
PathGenerator path(player);
|
||||
diagnostics.Calculated = path.CalculatePath(tx, ty, tz);
|
||||
diagnostics.PathType = uint32(path.GetPathType());
|
||||
|
||||
auto const& points = path.GetPath();
|
||||
diagnostics.PointCount = uint32(points.size());
|
||||
|
||||
if (!points.empty())
|
||||
{
|
||||
for (std::size_t i = 1; i < points.size(); ++i)
|
||||
{
|
||||
float const dx = points[i].x - points[i - 1].x;
|
||||
float const dy = points[i].y - points[i - 1].y;
|
||||
float const dz = points[i].z - points[i - 1].z;
|
||||
float const segment = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
diagnostics.PathLength += segment;
|
||||
diagnostics.MaxSegmentLength = std::max(diagnostics.MaxSegmentLength, segment);
|
||||
diagnostics.MaxZDelta = std::max(diagnostics.MaxZDelta, std::fabs(dz));
|
||||
}
|
||||
|
||||
auto const& last = points.back();
|
||||
float const dx = last.x - tx;
|
||||
float const dy = last.y - ty;
|
||||
float const dz = last.z - tz;
|
||||
diagnostics.FinalDistance = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
else
|
||||
diagnostics.FinalDistance = diagnostics.DirectDistance;
|
||||
|
||||
uint32 const pathType = diagnostics.PathType;
|
||||
diagnostics.Complete =
|
||||
diagnostics.Calculated &&
|
||||
(pathType & uint32(PATHFIND_NOPATH)) == 0 &&
|
||||
(pathType & uint32(PATHFIND_INCOMPLETE)) == 0;
|
||||
|
||||
auto addReason = [&](char const* reason)
|
||||
{
|
||||
if (!diagnostics.Reason.empty())
|
||||
diagnostics.Reason += ",";
|
||||
diagnostics.Reason += reason;
|
||||
diagnostics.Suspicious = true;
|
||||
};
|
||||
|
||||
if (!diagnostics.Calculated)
|
||||
addReason("calculate-failed");
|
||||
if (pathType & uint32(PATHFIND_NOPATH))
|
||||
addReason("no-path");
|
||||
if (pathType & uint32(PATHFIND_INCOMPLETE))
|
||||
addReason("incomplete");
|
||||
if (diagnostics.PointCount == 0 && diagnostics.DirectDistance > ARRIVAL_DISTANCE)
|
||||
addReason("empty-path");
|
||||
if (diagnostics.MaxSegmentLength > 25.0f)
|
||||
addReason("large-segment");
|
||||
if (diagnostics.MaxZDelta > 8.0f)
|
||||
addReason("large-z-delta");
|
||||
if (diagnostics.FinalDistance > 3.0f)
|
||||
addReason("far-from-target");
|
||||
if (diagnostics.DirectDistance > 5.0f && diagnostics.PathLength > diagnostics.DirectDistance * 8.0f)
|
||||
addReason("extreme-detour");
|
||||
|
||||
if (diagnostics.Reason.empty())
|
||||
diagnostics.Reason = "ok";
|
||||
|
||||
return diagnostics.Calculated;
|
||||
}
|
||||
|
||||
void ClientlessTravelMgr::LaunchPath(Player* player, TravelRecord& record)
|
||||
{
|
||||
if (!player)
|
||||
@@ -46,6 +142,49 @@ void ClientlessTravelMgr::LaunchPath(Player* player, TravelRecord& record)
|
||||
player->GetMotionMaster()->Clear();
|
||||
|
||||
Position const& target = record.Status.Target;
|
||||
|
||||
AnalyzePath(player, target, record.Status.Path);
|
||||
ClientlessPathDiagnostics const& nav = record.Status.Path;
|
||||
|
||||
if (nav.Suspicious)
|
||||
{
|
||||
TC_LOG_WARN("server.adventurebot",
|
||||
"[AdventureBot][Nav] path-suspicious guid=%u name='%s' map=%u "
|
||||
"start=(%.3f %.3f %.3f) target=(%.3f %.3f %.3f) "
|
||||
"type=0x%X calculated=%u complete=%u points=%u direct=%.2f path=%.2f "
|
||||
"maxSegment=%.2f maxZDelta=%.2f finalDistance=%.2f repath=%u reason='%s'",
|
||||
player->GetGUID().GetCounter(), player->GetName().c_str(), player->GetMapId(),
|
||||
player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),
|
||||
target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(),
|
||||
nav.PathType, nav.Calculated ? 1u : 0u, nav.Complete ? 1u : 0u,
|
||||
nav.PointCount, nav.DirectDistance, nav.PathLength,
|
||||
nav.MaxSegmentLength, nav.MaxZDelta, nav.FinalDistance,
|
||||
record.Status.RepathCount, nav.Reason.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_INFO("server.adventurebot",
|
||||
"[AdventureBot][Nav] path guid=%u name='%s' map=%u "
|
||||
"type=0x%X points=%u direct=%.2f path=%.2f maxSegment=%.2f "
|
||||
"maxZDelta=%.2f finalDistance=%.2f repath=%u",
|
||||
player->GetGUID().GetCounter(), player->GetName().c_str(), player->GetMapId(),
|
||||
nav.PathType, nav.PointCount, nav.DirectDistance, nav.PathLength,
|
||||
nav.MaxSegmentLength, nav.MaxZDelta, nav.FinalDistance,
|
||||
record.Status.RepathCount);
|
||||
}
|
||||
|
||||
PathGenerator debugPath(player);
|
||||
if (debugPath.CalculatePath(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()))
|
||||
{
|
||||
auto const& debugPoints = debugPath.GetPath();
|
||||
for (std::size_t i = 0; i < debugPoints.size(); ++i)
|
||||
TC_LOG_DEBUG("server.adventurebot",
|
||||
"[AdventureBot][Nav] path-point guid=%u repath=%u index=%u/%u xyz=(%.3f %.3f %.3f)",
|
||||
player->GetGUID().GetCounter(), record.Status.RepathCount,
|
||||
uint32(i + 1), uint32(debugPoints.size()),
|
||||
debugPoints[i].x, debugPoints[i].y, debugPoints[i].z);
|
||||
}
|
||||
|
||||
player->GetMotionMaster()->MovePoint(
|
||||
1,
|
||||
target.GetPositionX(),
|
||||
@@ -201,6 +340,12 @@ void ClientlessTravelMgr::Update(uint32 diff)
|
||||
TC_LOG_WARN("server.worldserver",
|
||||
"ClientlessTravel character GUID %u is stuck (remaining=%.2f, repaths=%u).",
|
||||
characterGuid, distance, record.Status.RepathCount);
|
||||
TC_LOG_WARN("server.adventurebot",
|
||||
"[AdventureBot][Nav] stuck guid=%u name='%s' map=%u remaining=%.2f "
|
||||
"repaths=%u lastPathType=0x%X lastPathPoints=%u lastReason='%s'",
|
||||
characterGuid, player->GetName().c_str(), player->GetMapId(), distance,
|
||||
record.Status.RepathCount, record.Status.Path.PathType,
|
||||
record.Status.Path.PointCount, record.Status.Path.Reason.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -210,6 +355,12 @@ void ClientlessTravelMgr::Update(uint32 diff)
|
||||
"ClientlessTravel repathing character GUID %u (remaining=%.2f, repath=%u/%u).",
|
||||
characterGuid, distance, record.Status.RepathCount, MAX_REPATHS);
|
||||
|
||||
TC_LOG_WARN("server.adventurebot",
|
||||
"[AdventureBot][Nav] repath guid=%u name='%s' map=%u remaining=%.2f "
|
||||
"noProgressMs=%u repath=%u/%u reason='no-progress'",
|
||||
characterGuid, player->GetName().c_str(), player->GetMapId(), distance,
|
||||
record.Status.NoProgressMs, record.Status.RepathCount, MAX_REPATHS);
|
||||
|
||||
LaunchPath(player, record);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,24 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Position.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
struct TC_GAME_API ClientlessPathDiagnostics
|
||||
{
|
||||
bool Calculated = false;
|
||||
bool Complete = false;
|
||||
bool Suspicious = false;
|
||||
uint32 PathType = 0;
|
||||
uint32 PointCount = 0;
|
||||
float DirectDistance = 0.0f;
|
||||
float PathLength = 0.0f;
|
||||
float MaxSegmentLength = 0.0f;
|
||||
float MaxZDelta = 0.0f;
|
||||
float FinalDistance = 0.0f;
|
||||
std::string Reason;
|
||||
};
|
||||
|
||||
class Player;
|
||||
|
||||
enum class ClientlessTravelState : uint8
|
||||
@@ -28,6 +44,7 @@ struct TC_GAME_API ClientlessTravelStatus
|
||||
float RemainingDistance = 0.0f;
|
||||
uint32 RepathCount = 0;
|
||||
uint32 NoProgressMs = 0;
|
||||
ClientlessPathDiagnostics Path;
|
||||
};
|
||||
|
||||
class TC_GAME_API ClientlessTravelMgr
|
||||
@@ -36,6 +53,7 @@ public:
|
||||
static ClientlessTravelMgr* instance();
|
||||
|
||||
bool StartTravel(Player* player, Position const& target);
|
||||
bool AnalyzePath(Player* player, Position const& target, ClientlessPathDiagnostics& diagnostics) const;
|
||||
void CancelTravel(uint32 characterGuid);
|
||||
ClientlessTravelStatus const* GetStatus(uint32 characterGuid) const;
|
||||
void Update(uint32 diff);
|
||||
|
||||
Reference in new issue
Block a user