implemented taxinodes
This commit is contained in:
1 parent
4c04cd88de
commit
24fb292cee
4 files changed
+547
-4
No files matched your search
@@ -95,6 +95,22 @@ namespace
|
||||
float parsed = std::strtof(value.c_str(), &end);
|
||||
return end && end != value.c_str() ? parsed : fallback;
|
||||
}
|
||||
|
||||
|
||||
bool ParseTaxiNodeKey(std::string const& key, uint32& taxiNodeId)
|
||||
{
|
||||
static std::string const Prefix = "taxi_";
|
||||
if (key.rfind(Prefix, 0) != 0 || key.size() <= Prefix.size())
|
||||
return false;
|
||||
|
||||
char* end = nullptr;
|
||||
unsigned long const parsed = std::strtoul(key.c_str() + Prefix.size(), &end, 10);
|
||||
if (!end || *end != '\0' || parsed == 0 || parsed > 0xFFFFFFFFul)
|
||||
return false;
|
||||
|
||||
taxiNodeId = uint32(parsed);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ClientlessActionExecutorMgr* ClientlessActionExecutorMgr::instance()
|
||||
@@ -480,6 +496,10 @@ bool ClientlessActionExecutorMgr::StartTravelToNode(
|
||||
record.Route.clear();
|
||||
record.RouteStep = 0;
|
||||
record.EdgePath.clear();
|
||||
record.TaxiActive = false;
|
||||
record.TaxiPathId = 0;
|
||||
record.TaxiSourceNodeId = 0;
|
||||
record.TaxiDestinationNodeId = 0;
|
||||
std::string error;
|
||||
if (!sClientlessTravelGraphMgr->PlanRoute(
|
||||
player, destinationNode, startRadius, record.Route, error))
|
||||
@@ -611,6 +631,10 @@ bool ClientlessActionExecutorMgr::StartTravelToLocation(
|
||||
record.Route.clear();
|
||||
record.RouteStep = 0;
|
||||
record.EdgePath.clear();
|
||||
record.TaxiActive = false;
|
||||
record.TaxiPathId = 0;
|
||||
record.TaxiSourceNodeId = 0;
|
||||
record.TaxiDestinationNodeId = 0;
|
||||
|
||||
std::string anchorNode;
|
||||
std::string error;
|
||||
@@ -725,7 +749,7 @@ bool ClientlessActionExecutorMgr::StartRouteStep(
|
||||
|
||||
ClientlessTravelRouteStep const& step = record.Route[record.RouteStep];
|
||||
|
||||
if (step.EdgeType != "start" && step.EdgeType != "ground")
|
||||
if (step.EdgeType != "start" && step.EdgeType != "ground" && step.EdgeType != "taxi")
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
@@ -741,6 +765,103 @@ bool ClientlessActionExecutorMgr::StartRouteStep(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (step.EdgeType == "taxi")
|
||||
{
|
||||
if (record.RouteStep == 0)
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.Detail = "taxi edge has no source route step";
|
||||
record.Active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientlessTravelRouteStep const& sourceStep = record.Route[record.RouteStep - 1];
|
||||
|
||||
uint32 sourceTaxiNodeId = 0;
|
||||
uint32 destinationTaxiNodeId = 0;
|
||||
if (!ParseTaxiNodeKey(sourceStep.NodeKey, sourceTaxiNodeId) ||
|
||||
!ParseTaxiNodeKey(step.NodeKey, destinationTaxiNodeId))
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
record.Status.Detail = "taxi edge endpoints are not taxi_<id> nodes";
|
||||
record.Active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 taxiPathId = 0;
|
||||
uint32 taxiCost = 0;
|
||||
sObjectMgr->GetTaxiPath(
|
||||
sourceTaxiNodeId,
|
||||
destinationTaxiNodeId,
|
||||
taxiPathId,
|
||||
taxiCost);
|
||||
|
||||
if (!taxiPathId)
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
record.Status.Detail =
|
||||
"Trinity has no taxi path " +
|
||||
std::to_string(sourceTaxiNodeId) + " -> " +
|
||||
std::to_string(destinationTaxiNodeId);
|
||||
record.Active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
sClientlessTravelMgr->CancelTravel(characterGuid);
|
||||
record.EdgePath.clear();
|
||||
|
||||
if (!player->ActivateTaxiPathTo(taxiPathId))
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
record.Status.Detail =
|
||||
"ActivateTaxiPathTo failed for path=" +
|
||||
std::to_string(taxiPathId) +
|
||||
" source=" + std::to_string(sourceTaxiNodeId) +
|
||||
" destination=" + std::to_string(destinationTaxiNodeId);
|
||||
record.Active = false;
|
||||
|
||||
TC_LOG_WARN("server.adventurebot",
|
||||
"[AdventureBot] taxi-start-failed guid=%u name='%s' path=%u source=%u destination=%u cost=%u",
|
||||
characterGuid,
|
||||
player->GetName().c_str(),
|
||||
taxiPathId,
|
||||
sourceTaxiNodeId,
|
||||
destinationTaxiNodeId,
|
||||
taxiCost);
|
||||
return false;
|
||||
}
|
||||
|
||||
record.TaxiActive = true;
|
||||
record.TaxiPathId = taxiPathId;
|
||||
record.TaxiSourceNodeId = sourceTaxiNodeId;
|
||||
record.TaxiDestinationNodeId = destinationTaxiNodeId;
|
||||
|
||||
record.Status.State = ClientlessActionExecutionState::Moving;
|
||||
record.Status.TargetName = "node:" + step.NodeKey;
|
||||
record.Status.TargetGuid = 0;
|
||||
record.Status.TargetEntry = 0;
|
||||
record.Status.Detail =
|
||||
"taxi path " + std::to_string(taxiPathId) +
|
||||
" " + std::to_string(sourceTaxiNodeId) +
|
||||
" -> " + std::to_string(destinationTaxiNodeId);
|
||||
|
||||
TC_LOG_INFO("server.adventurebot",
|
||||
"[AdventureBot] taxi-started guid=%u name='%s' routeStep=%u/%u path=%u source=%u destination=%u cost=%u",
|
||||
characterGuid,
|
||||
player->GetName().c_str(),
|
||||
uint32(record.RouteStep + 1),
|
||||
uint32(record.Route.size()),
|
||||
taxiPathId,
|
||||
sourceTaxiNodeId,
|
||||
destinationTaxiNodeId,
|
||||
taxiCost);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (step.MapId != player->GetMapId())
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
@@ -886,6 +1007,82 @@ void ClientlessActionExecutorMgr::UpdateTravelToNode(
|
||||
uint32 characterGuid,
|
||||
Record& record)
|
||||
{
|
||||
if (record.TaxiActive)
|
||||
{
|
||||
if (!player || !player->IsInWorld())
|
||||
return;
|
||||
|
||||
if (player->IsInFlight())
|
||||
return;
|
||||
|
||||
if (record.RouteStep >= record.Route.size())
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.Detail = "taxi route step index became invalid";
|
||||
record.Active = false;
|
||||
record.TaxiActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ClientlessTravelRouteStep const& destination = record.Route[record.RouteStep];
|
||||
|
||||
if (player->GetMapId() != destination.MapId)
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.Detail =
|
||||
"taxi ended on unexpected map; expected=" +
|
||||
std::to_string(destination.MapId) +
|
||||
" actual=" + std::to_string(player->GetMapId());
|
||||
record.Active = false;
|
||||
record.TaxiActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
float const dx = player->GetPositionX() - destination.X;
|
||||
float const dy = player->GetPositionY() - destination.Y;
|
||||
float const dz = player->GetPositionZ() - destination.Z;
|
||||
float const remaining = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
|
||||
constexpr float TaxiArrivalSanityRadius = 120.0f;
|
||||
if (remaining > TaxiArrivalSanityRadius)
|
||||
{
|
||||
record.Status.State = ClientlessActionExecutionState::Failed;
|
||||
record.Status.Detail =
|
||||
"taxi stopped away from destination node; remaining=" +
|
||||
std::to_string(remaining);
|
||||
record.Active = false;
|
||||
record.TaxiActive = false;
|
||||
|
||||
TC_LOG_WARN("server.adventurebot",
|
||||
"[AdventureBot] taxi-ended-away-from-node guid=%u name='%s' path=%u source=%u destination=%u remaining=%.2f",
|
||||
characterGuid,
|
||||
player->GetName().c_str(),
|
||||
record.TaxiPathId,
|
||||
record.TaxiSourceNodeId,
|
||||
record.TaxiDestinationNodeId,
|
||||
remaining);
|
||||
return;
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.adventurebot",
|
||||
"[AdventureBot] taxi-complete guid=%u name='%s' path=%u source=%u destination=%u remaining=%.2f",
|
||||
characterGuid,
|
||||
player->GetName().c_str(),
|
||||
record.TaxiPathId,
|
||||
record.TaxiSourceNodeId,
|
||||
record.TaxiDestinationNodeId,
|
||||
remaining);
|
||||
|
||||
record.TaxiActive = false;
|
||||
record.TaxiPathId = 0;
|
||||
record.TaxiSourceNodeId = 0;
|
||||
record.TaxiDestinationNodeId = 0;
|
||||
|
||||
++record.RouteStep;
|
||||
StartRouteStep(player, characterGuid, record);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!record.EdgePath.empty())
|
||||
{
|
||||
ClientlessTravelEdgePoint const& destination = record.EdgePath.back();
|
||||
|
||||
@@ -54,6 +54,12 @@ private:
|
||||
|
||||
std::vector<ClientlessTravelEdgePoint> EdgePath;
|
||||
|
||||
// C8.10b: active server-side taxi edge.
|
||||
bool TaxiActive = false;
|
||||
uint32 TaxiPathId = 0;
|
||||
uint32 TaxiSourceNodeId = 0;
|
||||
uint32 TaxiDestinationNodeId = 0;
|
||||
|
||||
bool FinalLocalLegPending = false;
|
||||
bool FinalLocalLegActive = false;
|
||||
uint32 FinalMapId = 0;
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
class Player;
|
||||
|
||||
// Canonical Vcore travel-node types:
|
||||
// ground, taxi, ship, zeppelin, tram, portal, elevator
|
||||
//
|
||||
// Node type describes what the place is. Edge type describes how travel occurs.
|
||||
// Ground edges may connect any node type; specialized edge executors may impose
|
||||
// stricter endpoint rules.
|
||||
struct TC_GAME_API ClientlessTravelNode
|
||||
{
|
||||
uint32 DatabaseId = 0;
|
||||
|
||||
Reference in new issue
Block a user