From 154d283d3a5c9048157a76009bf69308cb392c53 Mon Sep 17 00:00:00 2001 From: Ovalord <1Don7H4v3@m41L.com> Date: Mon, 12 Feb 2018 20:09:02 +0100 Subject: [PATCH] Core/Movement: *cyclic movement will now always use catmullrom and enter_cycle flags. Fixes visual issues when spline gets sent via update_object packet *MoveCirclePath motion master will now always make the creature fly. According to sniffs all cyclic moving creatures are flying *remove hack from cyclic monster_move packet. The first vertex is getting deleted by the client when using enter_cycle spline flag. *recalculate cycle path when completing first loop to get rid of the first vertex *implement SMSG_FLIGHT_SPLINE_SYNC opcode. according to sniffs this opcode gets sent every 5 seconds to fix client / server asynch movement issues. thx to Morgoporc for the unit.cpp part --- src/server/game/Entities/Unit/Unit.cpp | 34 ++++++++++++++++--- src/server/game/Entities/Unit/Unit.h | 3 ++ src/server/game/Movement/MotionMaster.cpp | 21 +++--------- .../game/Movement/Spline/MoveSpline.cpp | 25 +++++++++++--- src/server/game/Movement/Spline/MoveSpline.h | 4 ++- .../game/Movement/Spline/MoveSplineInit.cpp | 13 ++++++- .../Movement/Spline/MovementPacketBuilder.cpp | 3 +- 7 files changed, 75 insertions(+), 28 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index cc843ab42b..2be5859e2d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -486,20 +486,38 @@ void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool gen init.Launch(); } -void Unit::UpdateSplineMovement(uint32 t_diff) +void Unit::UpdateSplineMovement(uint32 p_diff) { + uint32 const flightSplineSyncDelay = 5 * TimeConstants::IN_MILLISECONDS; + + bool arrived = movespline->Finalized(); if (movespline->Finalized()) return; - movespline->updateState(t_diff); - bool arrived = movespline->Finalized(); + movespline->updateState(p_diff); + arrived = movespline->Finalized(); if (arrived) DisableSpline(); - m_movesplineTimer.Update(t_diff); + m_movesplineTimer.Update(p_diff); if (m_movesplineTimer.Passed() || arrived) UpdateSplinePosition(); + + m_FlightSplineSyncTimer.Update(p_diff); + if (m_FlightSplineSyncTimer.Passed()) + { + float percent = 1.0f; + float totalTime = movespline->Duration(); + if (totalTime > 0.0f) + percent = (float)movespline->timePassed() / totalTime; + + // Synch flight movement for cylic movement + if (movespline->isCyclic() && IsFlying()) + SendFlightSplineSync(percent); + + m_FlightSplineSyncTimer.Reset(flightSplineSyncDelay); + } } void Unit::UpdateSplinePosition() @@ -8984,6 +9002,14 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate) Movement::PacketSender(this, moveTypeToOpcode[mtype][0], moveTypeToOpcode[mtype][1], moveTypeToOpcode[mtype][2], &extra).Send(); } +void Unit::SendFlightSplineSync(float splineDist) +{ + WorldPacket data(SMSG_FLIGHT_SPLINE_SYNC, 11); + data << float(splineDist); + data.appendPackGUID(GetGUID()); + SendMessageToSet(&data, false); +} + void Unit::setDeathState(DeathState s) { // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e645946c46..af84d393e8 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1676,6 +1676,8 @@ class TC_GAME_API Unit : public WorldObject void SendClearTarget(); + void SendFlightSplineSync(float splineDist); + bool IsAlive() const { return (m_deathState == ALIVE); } bool isDying() const { return (m_deathState == JUST_DIED); } bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); } @@ -2338,6 +2340,7 @@ class TC_GAME_API Unit : public WorldObject uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; TimeTrackerSmall m_movesplineTimer; + TimeTrackerSmall m_FlightSplineSyncTimer; Diminishing m_Diminishing; // Manage all Units that are threatened by us diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 0a0a0a9039..7065fd8612 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -482,26 +482,15 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool G3D::Vector3 point; point.x = x + radius * cosf(angle); point.y = y + radius * sinf(angle); - - if (_owner->IsFlying()) - point.z = z; - else - point.z = _owner->GetMap()->GetHeight(_owner->GetPhases(), point.x, point.y, z); + point.z = z; init.Path().push_back(point); } - if (_owner->IsFlying()) - { - init.SetFly(); - init.SetCyclic(); - init.SetAnimation(Movement::ToFly); - } - else - { - init.SetWalk(true); - init.SetCyclic(); - } + init.SetFly(); // Cyclic movement is always flying + init.SetCyclic(); + init.SetUncompressed(); + init.SetAnimation(Movement::ToFly); init.Launch(); } diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 574b11aabb..985976299e 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -122,10 +122,10 @@ void MoveSpline::init_spline(const MoveSplineInitArgs& args) const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear, SplineBase::ModeCatmullrom}; if (args.flags.cyclic) { - uint32 cyclic_point = 0; - // MoveSplineFlag::Enter_Cycle support dropped - //if (splineflags & SPLINEFLAG_ENTER_CYCLE) - //cyclic_point = 1; // shouldn't be modified, came from client + // Cyclic movement always starts with Enter_Cycle flag. + // The first vertex is a fake circle point and needs to get + // removed once the first cycle is complete + uint32 cyclic_point = 1; spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point); } else @@ -173,6 +173,10 @@ void MoveSpline::Initialize(MoveSplineInitArgs const& args) return; } + // Copy arguments for cyclic paths to recalculate the cycle after first loop + if (args.flags.cyclic) + initCycleArgs = args; + init_spline(args); // init parabolic / animation @@ -265,6 +269,19 @@ MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff) { if (spline.isCyclic()) { + // Recalculate new cycle without first vertex + if (!initCycleArgs.path.empty()) + { + // First we remove the vertex from the path... + initCycleArgs.path.erase(initCycleArgs.path.begin()); + + // ...now we recalculate a new path... + const SplineBase::EvaluationMode modes[2] = { SplineBase::ModeLinear, SplineBase::ModeCatmullrom }; + spline.init_cyclic_spline(&initCycleArgs.path[0], initCycleArgs.path.size(), modes[initCycleArgs.flags.isSmooth()], 0); + + // ... and clear the path to avoid endless loops + initCycleArgs.path.clear(); + } point_Idx = spline.first(); time_passed = time_passed % Duration(); result = Result_NextCycle; diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h index f28f8a38e0..6fb9021441 100644 --- a/src/server/game/Movement/Spline/MoveSpline.h +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -59,6 +59,8 @@ namespace Movement MoveSplineFlag splineflags; + MoveSplineInitArgs initCycleArgs; + int32 time_passed; // currently duration mods are unused, but its _currently_ //float duration_mod; @@ -80,10 +82,10 @@ namespace Movement int32 next_timestamp() const { return spline.length(point_Idx + 1); } int32 segment_time_elapsed() const { return next_timestamp() - time_passed; } int32 timeElapsed() const { return Duration() - time_passed; } - int32 timePassed() const { return time_passed; } public: int32 Duration() const { return spline.length(); } + int32 timePassed() const { return time_passed; } MySpline const& _Spline() const { return spline; } int32 _currentSplineIdx() const { return point_Idx; } void _Finalize(); diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index 309a9e5b3d..5ec2979329 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -85,7 +85,18 @@ namespace Movement return 0; // correct first vertex - args.path[0] = real_position; + if (!args.flags.cyclic) + args.path[0] = real_position; + else + args.path.insert(args.path.begin(), real_position); + + // Cyclic movement always uses catmullrom and enter_cycle movement flag + if (args.flags.cyclic) + { + args.flags.EnableCatmullRom(); + args.flags.enter_cycle = true; + } + args.initialOrientation = real_position.orientation; move_spline.onTransport = (unit->GetTransGUID() != 0); diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index 381b41026f..94af81c1ec 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -127,8 +127,7 @@ namespace Movement void WriteUncompressedCyclicPath(Spline const& spline, ByteBuffer& data) { uint32 count = spline.getPointCount() - 3; - data << uint32(count + 1); - data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done + data << uint32(count); data.append(&spline.getPoint(1), count); }