From c7a96ab067523d270dbe7f35c39b9f34b5828cbb Mon Sep 17 00:00:00 2001 From: H0zen Date: Fri, 19 Feb 2016 01:06:54 +0200 Subject: [PATCH] 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 --- src/game/Object/GameObject.cpp | 22 ++++++- src/game/Object/GameObject.h | 2 + src/game/Object/Player.cpp | 17 +---- src/game/WorldHandlers/Map.cpp | 28 ++++++--- src/game/WorldHandlers/SpellHandler.cpp | 5 +- src/game/WorldHandlers/TaxiHandler.cpp | 82 +++++++++++++++---------- src/game/movement/MoveSpline.cpp | 1 + src/game/movement/packet_builder.cpp | 42 +++++-------- src/tools/Extractor_projects | 2 +- 9 files changed, 113 insertions(+), 88 deletions(-) diff --git a/src/game/Object/GameObject.cpp b/src/game/Object/GameObject.cpp index 3f8725e7..2580159d 100644 --- a/src/game/Object/GameObject.cpp +++ b/src/game/Object/GameObject.cpp @@ -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()); -} \ No newline at end of file +} + +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; +} diff --git a/src/game/Object/GameObject.h b/src/game/Object/GameObject.h index da7a671d..b70b48f0 100644 --- a/src/game/Object/GameObject.h +++ b/src/game/Object/GameObject.h @@ -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& GetGridRef() { return m_gridRef; } diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index df25e174..134ea99e 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -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; } diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index d78aae3e..ff1f4163 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -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; diff --git a/src/game/WorldHandlers/SpellHandler.cpp b/src/game/WorldHandlers/SpellHandler.cpp index 303bb1fb..24901524 100644 --- a/src/game/WorldHandlers/SpellHandler.cpp +++ b/src/game/WorldHandlers/SpellHandler.cpp @@ -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()) { diff --git a/src/game/WorldHandlers/TaxiHandler.cpp b/src/game/WorldHandlers/TaxiHandler.cpp index ecfdc142..0fa6b2ff 100644 --- a/src/game/WorldHandlers/TaxiHandler.cpp +++ b/src/game/WorldHandlers/TaxiHandler.cpp @@ -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); } diff --git a/src/game/movement/MoveSpline.cpp b/src/game/movement/MoveSpline.cpp index b44ecacd..b484bed2 100644 --- a/src/game/movement/MoveSpline.cpp +++ b/src/game/movement/MoveSpline.cpp @@ -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; } diff --git a/src/game/movement/packet_builder.cpp b/src/game/movement/packet_builder.cpp index 0fd67990..97edc65f 100644 --- a/src/game/movement/packet_builder.cpp +++ b/src/game/movement/packet_builder.cpp @@ -79,33 +79,19 @@ namespace Movement void WriteLinearPath(const Spline& 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(); diff --git a/src/tools/Extractor_projects b/src/tools/Extractor_projects index 8f492dbb..cde7ea4a 160000 --- a/src/tools/Extractor_projects +++ b/src/tools/Extractor_projects @@ -1 +1 @@ -Subproject commit 8f492dbbd39ddd79af2ce254f7dbf76b8564bf7a +Subproject commit cde7ea4a007a37347256cbbcb4f989145a7bb6d6