/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef TRINITYCORE_MOVEMENT_PACKETS_H
#define TRINITYCORE_MOVEMENT_PACKETS_H
#include "Packet.h"
#include "CombatLogPacketsCommon.h"
#include "MovementInfo.h"
#include "Optional.h"
namespace Movement
{
class MoveSpline;
}
namespace WorldPackets
{
namespace Movement
{
struct MovementAck
{
MovementInfo Status;
int32 AckIndex = 0;
};
class ClientPlayerMovement final : public ClientPacket
{
public:
explicit ClientPlayerMovement(WorldPacket&& packet) : ClientPacket(std::move(packet)) { }
void Read() override;
MovementInfo Status;
};
class TC_GAME_API MoveUpdate final : public ServerPacket
{
public:
explicit MoveUpdate() : ServerPacket(SMSG_MOVE_UPDATE) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
};
struct MonsterSplineFilterKey
{
int16 Idx = 0;
uint16 Speed = 0;
};
struct MonsterSplineFilter
{
std::vector FilterKeys;
uint8 FilterFlags = 0;
float BaseSpeed = 0.0f;
int16 StartOffset = 0;
float DistToPrevFilterKey = 0.0f;
int16 AddedToStart = 0;
};
struct MonsterSplineSpellEffectExtraData
{
ObjectGuid TargetGUID;
uint32 SpellVisualID = 0;
uint32 ProgressCurveID = 0;
uint32 ParabolicCurveID = 0;
float JumpGravity = 0.0f;
};
struct MonsterSplineJumpExtraData
{
float JumpGravity = 0.0f;
uint32 StartTime = 0;
uint32 Duration = 0;
};
struct MonsterSplineTurnData
{
float StartFacing = 0.0f;
float TotalTurnRads = 0.0f;
float RadsPerSec = 0.0f;
};
struct MonsterSplineAnimTierTransition
{
int32 TierTransitionID = 0;
uint32 StartTime = 0;
uint32 ExtraDuration = 0; ///< Duration of the transition (unit does not move during this time)
uint8 AnimTier = 0;
};
struct MonsterSplineUnknown901
{
struct Inner
{
int32 Unknown_1 = 0;
Spells::SpellCastVisual Visual;
uint32 Unknown_4 = 0;
};
std::array Data;
};
struct MovementSpline
{
uint32 Flags = 0; // Spline flags
uint8 Face = 0; // Movement direction (see MonsterMoveType enum)
int32 Elapsed = 0;
uint32 MoveTime = 0;
uint32 FadeObjectTime = 0;
std::vector> Points; // Spline path
uint8 Mode = 0; // Spline mode - actually always 0 in this packet - Catmullrom mode appears only in SMSG_UPDATE_OBJECT. In this packet it is determined by flags
bool VehicleExitVoluntary = false;
bool TaxiSmoothing = false;
ObjectGuid TransportGUID;
int8 VehicleSeat = -1;
std::vector> PackedDeltas;
Optional SplineFilter;
Optional SpellEffectExtraData;
Optional JumpExtraData;
Optional TurnData;
Optional AnimTierTransition;
Optional Unknown901;
float FaceDirection = 0.0f;
ObjectGuid FaceGUID;
TaggedPosition FaceSpot;
};
struct MovementMonsterSpline
{
uint32 ID = 0;
bool CrzTeleport = false;
bool StopUseFaceDirection = false;
uint8 StopSplineStyle = 0; // Determines how far from spline destination the mover is allowed to stop in place 0, 0, 3.0, 2.76, numeric_limits::max, 1.1, float(INT_MAX); default before this field existed was distance 3.0 (index 2)
MovementSpline Move;
};
class CommonMovement
{
public:
static void WriteCreateObjectSplineDataBlock(::Movement::MoveSpline const& moveSpline, ByteBuffer& data);
static void WriteMovementForceWithDirection(MovementForce const& movementForce, ByteBuffer& data, Position const* objectPosition = nullptr);
};
class MonsterMove final : public ServerPacket
{
public:
explicit MonsterMove() : ServerPacket(SMSG_ON_MONSTER_MOVE) { }
void InitializeSplineData(::Movement::MoveSpline const& moveSpline);
WorldPacket const* Write() override;
MovementMonsterSpline SplineData;
ObjectGuid MoverGUID;
TaggedPosition Pos;
};
class FlightSplineSync final : public ServerPacket
{
public:
explicit FlightSplineSync() : ServerPacket(SMSG_FLIGHT_SPLINE_SYNC, 16 + 4) { }
WorldPacket const* Write() override;
ObjectGuid Guid;
float SplineDist = 0.0f;
};
class MoveSplineSetSpeed : public ServerPacket
{
public:
explicit MoveSplineSetSpeed(OpcodeServer opcode) : ServerPacket(opcode, 12) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
float Speed = 1.0f;
};
class MoveSetSpeed : public ServerPacket
{
public:
explicit MoveSetSpeed(OpcodeServer opcode) : ServerPacket(opcode) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
uint32 SequenceIndex = 0; ///< Unit movement packet index, incremented each time
float Speed = 1.0f;
};
class MoveUpdateSpeed : public ServerPacket
{
public:
explicit MoveUpdateSpeed(OpcodeServer opcode) : ServerPacket(opcode) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
float Speed = 1.0f;
};
class SetAdvFlyingSpeed final : public ServerPacket
{
public:
explicit SetAdvFlyingSpeed(OpcodeServer opcode) : ServerPacket(opcode, 16 + 4 + 4) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
uint32 SequenceIndex = 0;
float Speed = 1.0f;
};
class SetAdvFlyingSpeedRange final : public ServerPacket
{
public:
explicit SetAdvFlyingSpeedRange(OpcodeServer opcode) : ServerPacket(opcode, 16 + 4 + 4 + 4) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
uint32 SequenceIndex = 0;
float SpeedMin = 1.0f;
float SpeedMax = 1.0f;
};
class MoveSplineSetFlag final : public ServerPacket
{
public:
explicit MoveSplineSetFlag(OpcodeServer opcode) : ServerPacket(opcode, 8) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
};
class MoveSetFlag final : public ServerPacket
{
public:
explicit MoveSetFlag(OpcodeServer opcode) : ServerPacket(opcode, 12) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
uint32 SequenceIndex = 0; ///< Unit movement packet index, incremented each time
};
struct ShipTransferPending
{
uint32 ID = 0; ///< gameobject_template.entry of the transport the player is teleporting on
int32 OriginMapID = -1; ///< Map id the player is currently on (before teleport)
};
class TransferPending final : public ServerPacket
{
public:
explicit TransferPending() : ServerPacket(SMSG_TRANSFER_PENDING, 16) { }
WorldPacket const* Write() override;
int32 MapID = -1;
TaggedPosition OldMapPosition;
Optional Ship;
Optional TransferSpellID;
Optional TaxiPathID;
};
class TransferAborted final : public ServerPacket
{
public:
explicit TransferAborted() : ServerPacket(SMSG_TRANSFER_ABORTED, 4 + 1 + 4 + 1) { }
WorldPacket const* Write() override;
uint32 MapID = 0;
uint8 Arg = 0;
int32 MapDifficultyXConditionID = 0;
uint32 TransfertAbort = 0;
};
struct TeleportLocation
{
TaggedPosition Pos;
int32 FloorDifficulty = -1;
int32 FloorIndex = -1;
};
class NewWorld final : public ServerPacket
{
public:
explicit NewWorld() : ServerPacket(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4) { }
WorldPacket const* Write() override;
int32 MapID = 0;
uint32 Reason = 0;
TeleportLocation Loc;
TaggedPosition MovementOffset; // Adjusts all pending movement events by this offset
int32 Counter = 0;
};
class WorldPortResponse final : public ClientPacket
{
public:
explicit WorldPortResponse(WorldPacket&& packet) : ClientPacket(CMSG_WORLD_PORT_RESPONSE, std::move(packet)) { }
void Read() override { }
};
struct VehicleTeleport
{
uint8 VehicleSeatIndex = 0;
bool VehicleExitVoluntary = false;
bool VehicleExitTeleport = false;
};
class MoveTeleport final : public ServerPacket
{
public:
explicit MoveTeleport() : ServerPacket(SMSG_MOVE_TELEPORT, 12+4+16+16+4) { }
WorldPacket const* Write() override;
TaggedPosition Pos;
Optional Vehicle;
uint32 SequenceIndex = 0;
ObjectGuid MoverGUID;
Optional TransportGUID;
float Facing = 0.0f;
uint8 PreloadWorld = 0;
};
class MoveUpdateTeleport final : public ServerPacket
{
public:
explicit MoveUpdateTeleport() : ServerPacket(SMSG_MOVE_UPDATE_TELEPORT) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
::MovementForces::Container const* MovementForces = nullptr;
Optional SwimBackSpeed;
Optional FlightSpeed;
Optional SwimSpeed;
Optional WalkSpeed;
Optional TurnRate;
Optional RunSpeed;
Optional FlightBackSpeed;
Optional RunBackSpeed;
Optional PitchRate;
};
class MoveApplyMovementForce final : public ServerPacket
{
public:
explicit MoveApplyMovementForce() : ServerPacket(SMSG_MOVE_APPLY_MOVEMENT_FORCE, 16 + 4 + 16 + 12 + 12 + 4 + 4 + 1) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
int32 SequenceIndex = 0;
MovementForce const* Force = nullptr;
};
class MoveApplyMovementForceAck final : public ClientPacket
{
public:
explicit MoveApplyMovementForceAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_APPLY_MOVEMENT_FORCE_ACK, std::move(packet)) { }
void Read() override;
MovementAck Ack;
MovementForce Force;
};
class MoveRemoveMovementForce final : public ServerPacket
{
public:
explicit MoveRemoveMovementForce() : ServerPacket(SMSG_MOVE_REMOVE_MOVEMENT_FORCE, 16 + 4 + 16) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
int32 SequenceIndex = 0;
ObjectGuid ID;
};
class MoveRemoveMovementForceAck final : public ClientPacket
{
public:
explicit MoveRemoveMovementForceAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_REMOVE_MOVEMENT_FORCE_ACK, std::move(packet)) { }
void Read() override;
MovementAck Ack;
ObjectGuid ID;
};
class MoveUpdateApplyMovementForce final : public ServerPacket
{
public:
explicit MoveUpdateApplyMovementForce() : ServerPacket(SMSG_MOVE_UPDATE_APPLY_MOVEMENT_FORCE, sizeof(MovementInfo) + 16 + 12 + 12 + 4 + 4 + 1) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
MovementForce const* Force = nullptr;
};
class MoveUpdateRemoveMovementForce final : public ServerPacket
{
public:
explicit MoveUpdateRemoveMovementForce() : ServerPacket(SMSG_MOVE_UPDATE_REMOVE_MOVEMENT_FORCE, sizeof(MovementInfo) + 16) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
ObjectGuid TriggerGUID;
};
class MoveTeleportAck final : public ClientPacket
{
public:
explicit MoveTeleportAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_TELEPORT_ACK, std::move(packet)) { }
void Read() override;
ObjectGuid MoverGUID;
int32 AckIndex = 0;
int32 MoveTime = 0;
};
class MovementAckMessage final : public ClientPacket
{
public:
explicit MovementAckMessage(WorldPacket&& packet) : ClientPacket(std::move(packet)) { }
void Read() override;
MovementAck Ack;
};
class MovementSpeedAck final : public ClientPacket
{
public:
explicit MovementSpeedAck(WorldPacket&& packet) : ClientPacket(std::move(packet)) { }
void Read() override;
MovementAck Ack;
float Speed = 0.0f;
};
class MovementSpeedRangeAck final : public ClientPacket
{
public:
explicit MovementSpeedRangeAck(WorldPacket&& packet) : ClientPacket(std::move(packet)) { }
void Read() override;
MovementAck Ack;
float SpeedMin = 1.0f;
float SpeedMax = 1.0f;
};
class SetActiveMover final : public ClientPacket
{
public:
explicit SetActiveMover(WorldPacket&& packet) : ClientPacket(CMSG_SET_ACTIVE_MOVER, std::move(packet)) { }
void Read() override;
ObjectGuid ActiveMover;
};
class MoveSetActiveMover final : public ServerPacket
{
public:
explicit MoveSetActiveMover() : ServerPacket(SMSG_MOVE_SET_ACTIVE_MOVER, 8) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
};
struct MoveKnockBackSpeeds
{
float HorzSpeed = 0.0f;
float VertSpeed = 0.0f;
};
class MoveKnockBack final : public ServerPacket
{
public:
explicit MoveKnockBack() : ServerPacket(SMSG_MOVE_KNOCK_BACK, 16 + 8 + 4 + 4 + 4) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
TaggedPosition Direction;
MoveKnockBackSpeeds Speeds;
uint32 SequenceIndex = 0;
};
class MoveUpdateKnockBack final : public ServerPacket
{
public:
explicit MoveUpdateKnockBack() : ServerPacket(SMSG_MOVE_UPDATE_KNOCK_BACK) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
};
class MoveKnockBackAck final : public ClientPacket
{
public:
explicit MoveKnockBackAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_KNOCK_BACK_ACK, std::move(packet)) { }
void Read() override;
MovementAck Ack;
Optional Speeds;
};
enum class UpdateCollisionHeightReason : uint8
{
Scale = 0,
Mount = 1,
Force = 2
};
class MoveSetCollisionHeight final : public ServerPacket
{
public:
explicit MoveSetCollisionHeight() : ServerPacket(SMSG_MOVE_SET_COLLISION_HEIGHT, 4 + 16 + 4 + 1 + 4 + 4) { }
WorldPacket const* Write() override;
float Scale = 1.0f;
ObjectGuid MoverGUID;
uint32 MountDisplayID = 0;
UpdateCollisionHeightReason Reason = UpdateCollisionHeightReason::Scale;
uint32 SequenceIndex = 0;
int32 ScaleDuration = 0;
float Height = 1.0f;
};
class MoveUpdateCollisionHeight final : public ServerPacket
{
public:
explicit MoveUpdateCollisionHeight() : ServerPacket(SMSG_MOVE_UPDATE_COLLISION_HEIGHT) { }
WorldPacket const* Write() override;
MovementInfo* Status = nullptr;
float Scale = 1.0f;
float Height = 1.0f;
};
class MoveSetCollisionHeightAck final : public ClientPacket
{
public:
explicit MoveSetCollisionHeightAck(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_SET_COLLISION_HEIGHT_ACK, std::move(packet)) { }
void Read() override;
MovementAck Data;
UpdateCollisionHeightReason Reason = UpdateCollisionHeightReason::Scale;
uint32 MountDisplayID = 0;
float Height = 1.0f;
};
class MoveTimeSkipped final : public ClientPacket
{
public:
explicit MoveTimeSkipped(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_TIME_SKIPPED, std::move(packet)) { }
void Read() override;
ObjectGuid MoverGUID;
uint32 TimeSkipped = 0;
};
class MoveSkipTime final : public ServerPacket
{
public:
explicit MoveSkipTime() : ServerPacket(SMSG_MOVE_SKIP_TIME, 16 + 4) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
uint32 TimeSkipped = 0;
};
class SummonResponse final : public ClientPacket
{
public:
explicit SummonResponse(WorldPacket&& packet) : ClientPacket(CMSG_SUMMON_RESPONSE, std::move(packet)) { }
void Read() override;
bool Accept = false;
ObjectGuid SummonerGUID;
};
class TC_GAME_API ControlUpdate final : public ServerPacket
{
public:
explicit ControlUpdate() : ServerPacket(SMSG_CONTROL_UPDATE, 16 + 1) { }
WorldPacket const* Write() override;
ObjectGuid Guid;
bool On = false;
};
class MoveSplineDone final : public ClientPacket
{
public:
explicit MoveSplineDone(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_SPLINE_DONE, std::move(packet)) { }
void Read() override;
MovementInfo Status;
int32 SplineID = 0;
};
class SummonRequest final : public ServerPacket
{
public:
enum SummonReason : uint8
{
SPELL = 0,
SCENARIO = 1
};
explicit SummonRequest() : ServerPacket(SMSG_SUMMON_REQUEST, 16 + 4 + 4 + 1) { }
WorldPacket const* Write() override;
ObjectGuid SummonerGUID;
uint32 SummonerVirtualRealmAddress = 0;
int32 AreaID = 0;
SummonReason Reason = SPELL;
bool SkipStartingArea = false;
};
class SuspendToken final : public ServerPacket
{
public:
explicit SuspendToken() : ServerPacket(SMSG_SUSPEND_TOKEN, 4 + 1) { }
WorldPacket const* Write() override;
uint32 SequenceIndex = 1;
uint32 Reason = 1;
};
class SuspendTokenResponse final : public ClientPacket
{
public:
explicit SuspendTokenResponse(WorldPacket&& packet) : ClientPacket(CMSG_SUSPEND_TOKEN_RESPONSE, std::move(packet)) { }
void Read() override;
uint32 SequenceIndex = 0;
};
class ResumeToken final : public ServerPacket
{
public:
explicit ResumeToken() : ServerPacket(SMSG_RESUME_TOKEN, 4 + 1) { }
WorldPacket const* Write() override;
uint32 SequenceIndex = 1;
uint32 Reason = 1;
};
struct CollisionHeightInfo
{
float Height = 0.0f;
float Scale = 0.0f;
UpdateCollisionHeightReason Reason = UpdateCollisionHeightReason::Scale;
};
struct StateChangeRangeInfo
{
float Min = 0.0f;
float Max = 0.0f;
};
struct KnockBackInfo
{
float HorzSpeed = 0.0f;
TaggedPosition Direction;
float InitVertSpeed = 0.0f;
};
struct MoveStateChange
{
MoveStateChange(OpcodeServer messageId, uint32 sequenceIndex) : MessageID(messageId), SequenceIndex(sequenceIndex) { }
uint32 MessageID = 0;
uint32 SequenceIndex = 0;
Optional Speed;
Optional Range;
Optional KnockBack;
Optional VehicleRecID;
Optional CollisionHeight;
Optional MovementForce_;
Optional MovementForceGUID;
Optional MovementInertiaID;
Optional MovementInertiaLifetimeMs;
Optional DriveCapabilityRecID;
};
class MoveSetCompoundState final : public ServerPacket
{
public:
explicit MoveSetCompoundState() : ServerPacket(SMSG_MOVE_SET_COMPOUND_STATE, 4 + 1) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
std::vector StateChanges;
};
class MoveInitActiveMoverComplete final : public ClientPacket
{
public:
explicit MoveInitActiveMoverComplete(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE, std::move(packet)) { }
void Read() override;
uint32 Ticks = 0;
};
ByteBuffer& operator>>(ByteBuffer& data, MovementAck& ack);
}
}
ByteBuffer& operator>>(ByteBuffer& data, MovementInfo& movementInfo);
ByteBuffer& operator<<(ByteBuffer& data, MovementInfo::TransportInfo const& transportInfo);
#endif // TRINITYCORE_MOVEMENT_PACKETS_H