Various external fixes - part 3

- ported commits from cmangos repositories
    - also:
        + fix Movement::MoveSpline::ComputePosition to return only positive angles
        + improved algorithm for finding a random reachable point on ground
This commit is contained in:
H0zen 2016-02-19 01:06:54 +02:00
parent 78c5faed9d
commit c7a96ab067
9 changed files with 113 additions and 88 deletions

View File

@ -2266,4 +2266,24 @@ void GameObject::TickCapturePoint()
uint32 GameObject::GetScriptId()
{
return sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) ? sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, -int32(GetGUIDLow())) : sScriptMgr.GetBoundScriptId(SCRIPTED_GAMEOBJECT, GetEntry());
}
}
float GameObject::GetInteractionDistance() const
{
float maxdist = INTERACTION_DISTANCE;
switch (GetGoType())
{
// TODO: find out how the client calculates the maximal usage distance to spellless working
// gameobjects like mailboxes - 10.0 is a just an abitrary choosen number
case GAMEOBJECT_TYPE_MAILBOX:
maxdist = 10.0f;
break;
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_FISHINGNODE:
maxdist = 20.0f + CONTACT_DISTANCE; // max spell range
break;
default:
break;
}
return maxdist;
}

View File

@ -697,6 +697,8 @@ class GameObject : public WorldObject
void SetCapturePointSlider(float value, bool isLocked);
float GetCapturePointSliderValue() const { return m_captureSlider; }
float GetInteractionDistance() const; // Get the maximum distance for a GO to interact with
uint32 GetScriptId();
GridReference<GameObject>& GetGridRef() { return m_gridRef; }

View File

@ -2072,22 +2072,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo
{
if (uint32(go->GetGoType()) == gameobject_type || gameobject_type == MAX_GAMEOBJECT_TYPE)
{
float maxdist;
switch (go->GetGoType())
{
// TODO: find out how the client calculates the maximal usage distance to spellless working
// gameobjects like mailboxes - 10.0 is a just an abitrary choosen number
case GAMEOBJECT_TYPE_MAILBOX:
maxdist = 10.0f;
break;
case GAMEOBJECT_TYPE_FISHINGHOLE:
maxdist = 20.0f + CONTACT_DISTANCE; // max spell range
break;
default:
maxdist = INTERACTION_DISTANCE;
break;
}
float maxdist = go->GetInteractionDistance();
if (go->IsWithinDistInMap(this, maxdist) && go->isSpawned())
{ return go; }

View File

@ -2213,25 +2213,39 @@ bool Map::GetReachableRandomPointOnGround(float& x, float& y, float& z, float ra
return false;
// here we have a valid position but the point can have a big Z in some case
// next code will check angle from 2 points
// next code will check angle from 2 points of view: x-axis and y-axis movement
// c
// /|
// / |
// b/__|a
// project vector to get only positive value
float ab = fabs(x - i_x);
float ac = fabs(z - i_z);
float delta = 0;
// slope represented by c angle (in radian)
// slope represented by b angle (in radian)
float slope = 0;
const float MAX_SLOPE_IN_RADIAN = 50.0f / 180.0f * M_PI_F; // 50(degree) max seem best value for walkable slope
// check ab vector to avoid divide by 0
if (ab > 0.0f)
delta = fabs(x - i_x); // check x-axis movement
if (delta > 0.0f) // check to avoid divide by 0
{
// compute c angle and convert it from radian to degree
slope = atan(ac / ab);
// compute slope
slope = atan(ac / delta);
if (slope < MAX_SLOPE_IN_RADIAN)
{
x = i_x;
y = i_y;
z = i_z;
return true;
}
}
delta = fabs(y - i_y); // check y-axis movement
if (delta > 0.0f) // check to avoid divide by 0
{
// compute slope
slope = atan(ac / delta);
if (slope < MAX_SLOPE_IN_RADIAN)
{
x = i_x;

View File

@ -256,10 +256,13 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recv_data)
if (!_player->IsSelfMover())
{ return; }
GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid);
GameObject* obj = _player->GetMap()->GetGameObject(guid);
if (!obj)
{ return; }
if (!obj->IsWithinDistInMap(_player, obj->GetInteractionDistance()))
{ return; }
// Additional check preventing exploits (ie loot despawned chests)
if (!obj->isSpawned())
{

View File

@ -47,14 +47,14 @@ void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recv_data)
void WorldSession::SendTaxiStatus(ObjectGuid guid)
{
// cheating checks
Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
Creature* unit = _player->GetMap()->GetCreature(guid);
if (!unit)
{
DEBUG_LOG("WorldSession::SendTaxiStatus - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam());
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), _player->GetTeam());
// not found nearest
if (curloc == 0)
@ -64,7 +64,7 @@ void WorldSession::SendTaxiStatus(ObjectGuid guid)
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
data << ObjectGuid(guid);
data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0);
data << uint8(_player->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0);
SendPacket(&data);
DEBUG_LOG("WORLD: Sent SMSG_TAXINODE_STATUS");
@ -78,7 +78,7 @@ void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket& recv_data)
recv_data >> guid;
// cheating checks
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
Creature* unit = _player->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!unit)
{
DEBUG_LOG("WORLD: HandleTaxiQueryAvailableNodes - %s not found or you can't interact with him.", guid.GetString().c_str());
@ -86,8 +86,8 @@ void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket& recv_data)
}
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
{ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
if (_player->hasUnitState(UNIT_STAT_DIED))
{ _player->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
// unknown taxi node case
if (SendLearnNewTaxiNode(unit))
@ -100,7 +100,7 @@ void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket& recv_data)
void WorldSession::SendTaxiMenu(Creature* unit)
{
// find current node
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam());
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), _player->GetTeam());
if (curloc == 0)
{ return; }
@ -111,7 +111,7 @@ void WorldSession::SendTaxiMenu(Creature* unit)
data << uint32(1);
data << unit->GetObjectGuid();
data << uint32(curloc);
GetPlayer()->m_taxi.AppendTaximaskTo(data, GetPlayer()->IsTaxiCheater());
_player->m_taxi.AppendTaximaskTo(data, _player->IsTaxiCheater());
SendPacket(&data);
DEBUG_LOG("WORLD: Sent SMSG_SHOWTAXINODES");
@ -120,27 +120,27 @@ void WorldSession::SendTaxiMenu(Creature* unit)
void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode)
{
// remove fake death
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
{ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
if (_player->hasUnitState(UNIT_STAT_DIED))
{ _player->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
{ GetPlayer()->GetMotionMaster()->MovementExpired(false); }
while (_player->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
{ _player->GetMotionMaster()->MovementExpired(false); }
if (mountDisplayId)
{ GetPlayer()->Mount(mountDisplayId); }
{ _player->Mount(mountDisplayId); }
GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path, pathNode);
_player->GetMotionMaster()->MoveTaxiFlight(path, pathNode);
}
bool WorldSession::SendLearnNewTaxiNode(Creature* unit)
{
// find current node
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam());
uint32 curloc = sObjectMgr.GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), _player->GetTeam());
if (curloc == 0)
{ return true; } // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result.
if (GetPlayer()->m_taxi.SetTaximaskNode(curloc))
if (_player->m_taxi.SetTaximaskNode(curloc))
{
WorldPacket msg(SMSG_NEW_TAXI_PATH, 0);
SendPacket(&msg);
@ -174,7 +174,7 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recv_data)
recv_data >> guid >> _totalcost >> node_count;
Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
Creature* npc = _player->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!npc)
{
DEBUG_LOG("WORLD: HandleActivateTaxiExpressOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
@ -186,6 +186,13 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recv_data)
{
uint32 node;
recv_data >> node;
if (!_player->m_taxi.IsTaximaskNodeKnown(node) && !_player->IsTaxiCheater())
{
SendActivateTaxiReply(ERR_TAXINOTVISITED);
recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet
return;
}
nodes.push_back(node);
}
@ -194,7 +201,7 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recv_data)
DEBUG_LOG("WORLD: Received opcode CMSG_ACTIVATETAXIEXPRESS from %d to %d" , nodes.front(), nodes.back());
GetPlayer()->ActivateTaxiPathTo(nodes, npc);
_player->ActivateTaxiPathTo(nodes, npc);
}
void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data)
@ -212,41 +219,41 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data)
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multi-map taxi path
// we need process only (1)
uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
uint32 curDest = _player->m_taxi.GetTaxiDestination();
if (!curDest)
{ return; }
TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
// far teleport case
if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId())
if (curDestNode && curDestNode->map_id != _player->GetMapId())
{
if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
if (_player->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
{
// short preparations to continue flight
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(_player->GetMotionMaster()->top());
flight->Interrupt(*GetPlayer()); // will reset at map landing
flight->Interrupt(*_player); // will reset at map landing
flight->SetCurrentNodeAfterTeleport();
TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation());
_player->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, _player->GetOrientation());
}
return;
}
uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination();
uint32 destinationnode = _player->m_taxi.NextTaxiDestination();
if (destinationnode > 0) // if more destinations to go
{
// current source node for next destination
uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource();
uint32 sourcenode = _player->m_taxi.GetTaxiSource();
// Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path)
if (GetPlayer()->IsTaxiCheater())
if (_player->IsTaxiCheater())
{
if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode))
if (_player->m_taxi.SetTaximaskNode(sourcenode))
{
WorldPacket data(SMSG_NEW_TAXI_PATH, 0);
_player->GetSession()->SendPacket(&data);
@ -255,7 +262,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data)
DEBUG_LOG("WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode);
uint32 mountDisplayId = sObjectMgr.GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam());
uint32 mountDisplayId = sObjectMgr.GetTaxiMountDisplayId(sourcenode, _player->GetTeam());
uint32 path, cost;
sObjectMgr.GetTaxiPath(sourcenode, destinationnode, path, cost);
@ -263,10 +270,10 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data)
if (path && mountDisplayId)
{ SendDoFlight(mountDisplayId, path, 1); } // skip start fly node
else
{ GetPlayer()->m_taxi.ClearTaxiDestinations(); } // clear problematic path and next
{ _player->m_taxi.ClearTaxiDestinations(); } // clear problematic path and next
}
else
{ GetPlayer()->m_taxi.ClearTaxiDestinations(); } // not destinations, clear source node
{ _player->m_taxi.ClearTaxiDestinations(); } // not destinations, clear source node
}
void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recv_data)
@ -279,12 +286,19 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recv_data)
recv_data >> guid >> nodes[0] >> nodes[1];
DEBUG_LOG("WORLD: Received opcode CMSG_ACTIVATETAXI from %d to %d" , nodes[0], nodes[1]);
Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
Creature* npc = _player->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
if (!npc)
{
DEBUG_LOG("WORLD: HandleActivateTaxiOpcode - %s not found or you can't interact with it.", guid.GetString().c_str());
return;
}
GetPlayer()->ActivateTaxiPathTo(nodes, npc);
if (!_player->IsTaxiCheater())
{
if (!_player->m_taxi.IsTaximaskNodeKnown(nodes[0]) || !_player->m_taxi.IsTaximaskNodeKnown(nodes[1]))
{
SendActivateTaxiReply(ERR_TAXINOTVISITED);
return;
}
}
_player->ActivateTaxiPathTo(nodes, npc);
}

View File

@ -61,6 +61,7 @@ namespace Movement
spline.evaluate_derivative(point_Idx, u, hermite);
c.orientation = atan2(hermite.y, hermite.x);
}
c.orientation = G3D::wrap(c.orientation, 0.f, (float)G3D::twoPi());
return c;
}

View File

@ -79,33 +79,19 @@ namespace Movement
void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 pointCount = spline.getPointCount() - 3;
uint32 last_idx = pointCount;
const Vector3* real_path = &spline.getPoint(1);
Vector3 destination = real_path[last_idx];
Movement::SplineBase::ControlArray const& pathPoint = spline.getPoints(); // get ref of whole path points array
size_t lastIndexPos = data.wpos();
data << last_idx;
uint32 pathSize = spline.last() - spline.first() - 1; // -1 as we send destination first and last index is destination
MANGOS_ASSERT(pathSize >= 0); // should never be less than 0
Vector3 destination = pathPoint[spline.last()]; // destination of this path should be send right after path size
data << pathSize;
data << destination;
if (last_idx > 1)
for (uint32 i = spline.first(); i < spline.first() + pathSize; i++) // from first real index (this array contain also special data)
{
Vector3 offset;
// first and last points already appended
for (uint32 i = 1; i < pointCount; ++i)
{
offset = destination - real_path[i];
// TODO: check if there is a better way to handle this like reworking path formatting to avoid generating such zero offset
// [-CLASSIC] The client freezes or crashes when it gets a zero offset.
// If the offset would be rounded to zero, skip it.
if (fabs(offset.x) < 0.25 && fabs(offset.y) < 0.25 && fabs(offset.z) < 0.25)
{
// Remove 1 from the counter that will be sent to the client.
last_idx--;
data.put(lastIndexPos, last_idx);
continue;
}
data.appendPackXYZ(offset.x, offset.y, offset.z);
}
Vector3 offset = destination - pathPoint[i]; // we have to send offset relative to destination instead of directly path point.
data.appendPackXYZ(offset.x, offset.y, offset.z); // we have to pack x,y,z before send
}
}
@ -151,17 +137,17 @@ namespace Movement
data << splineFlags.raw();
if (splineFlags.final_angle)
if (splineFlags.final_point)
{
data << move_spline.facing.angle;
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
}
else if (splineFlags.final_target)
{
data << move_spline.facing.target;
}
else if (splineFlags.final_point)
else if (splineFlags.final_angle)
{
data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z;
data << move_spline.facing.angle;
}
data << move_spline.timePassed();

@ -1 +1 @@
Subproject commit 8f492dbbd39ddd79af2ce254f7dbf76b8564bf7a
Subproject commit cde7ea4a007a37347256cbbcb4f989145a7bb6d6