diff options
| -rwxr-xr-x | src/server/game/AI/CoreAI/PetAI.cpp | 3 | ||||
| -rwxr-xr-x | src/server/game/DataStores/DBCStructure.h | 2 | ||||
| -rwxr-xr-x | src/server/game/DataStores/DBCfmt.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Entities/Object/Object.h | 4 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.cpp | 18 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.h | 7 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 35 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 9 | ||||
| -rwxr-xr-x | src/server/game/Handlers/MiscHandler.cpp | 6 | ||||
| -rwxr-xr-x | src/server/game/Handlers/MovementHandler.cpp | 25 | ||||
| -rw-r--r-- | src/server/game/Handlers/VehicleHandler.cpp | 17 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Opcodes.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Server/WorldSession.cpp | 38 | ||||
| -rwxr-xr-x | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 42 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 10 |
15 files changed, 176 insertions, 44 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index eedba4d8b7e..295768f9d3e 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -278,6 +278,7 @@ void PetAI::KilledUnit(Unit* victim) // next target selection me->AttackStop(); me->GetCharmInfo()->SetIsCommandAttack(false); + me->SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing Unit* nextTarget = SelectNextTarget(); @@ -457,7 +458,7 @@ bool PetAI::CanAttack(Unit* target) // Stay - can attack if target is within range or commanded to if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) - return (me->IsWithinMeleeRange(target, MIN_MELEE_REACH) || me->GetCharmInfo()->IsCommandAttack()); + return (me->IsWithinMeleeRange(target, MELEE_RANGE) || me->GetCharmInfo()->IsCommandAttack()); // Follow if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index d25578e304a..38e8c957681 100755 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1396,7 +1396,7 @@ struct ScalingStatValuesEntry uint32 spellPower; // 16 spell power for level uint32 ssdMultiplier2; // 17 there's data from 3.1 dbc ssdMultiplier[3] uint32 ssdMultiplier3; // 18 3.3 - uint32 armorMod2[5]; // 20-23 Armor for level + uint32 armorMod2[5]; // 19-23 Armor for level uint32 getssdMultiplier(uint32 mask) const { diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index ce887cac09b..39d031e96f9 100755 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -91,7 +91,7 @@ const char QuestFactionRewardfmt[]="niiiiiiiiii"; const char PvPDifficultyfmt[]="diiiii"; const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiii"; -const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiixiiii"; +const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiii"; const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; const char SkillLineAbilityfmt[]="niiiixxiiiiixx"; const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index fd8deb1b841..24ddd7973ab 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -482,6 +482,9 @@ struct MovementInfo // spline float splineElevation; + //! Server side only: + bool Violated; + MovementInfo() { pos.Relocate(0, 0, 0, 0); @@ -494,6 +497,7 @@ struct MovementInfo t_guid = 0; t_pos.Relocate(0, 0, 0, 0); t_seat = -1; + Violated = false; } uint32 GetMovementFlags() { return flags; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f0b974fa673..ffa216dd605 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -25173,3 +25173,21 @@ bool Player::SetHover(bool enable) return true; } + +void Player::SendMovementSetCanFly(bool apply) +{ + WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12); + data.append(GetPackGUID()); + data << uint32(0); //! movement counter + SendDirectMessage(&data); +} + +void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) +{ + WorldPacket data(apply ? + SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY : + SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, 12); + data.append(GetPackGUID()); + data << uint32(0); //! movement counter + SendDirectMessage(&data); +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7f6b2322e93..a238247b3c1 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2483,6 +2483,13 @@ class Player : public Unit, public GridObject<Player> #pragma region Player Movement + + /*! These methods send different packets to the client in apply and unapply case. + These methods are only sent to the current unit. + */ + void SendMovementSetCanFly(bool apply); + void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply); + bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } //! Return collision height sent to client diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b60abc18753..1bf8334ae79 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -17043,6 +17043,8 @@ void Unit::_ExitVehicle(Position const* exitPosition) else pos = *exitPosition; + AddUnitState(UNIT_STATE_MOVE); + if (GetTypeId() == TYPEID_PLAYER) ToPlayer()->SetFallInformation(0, GetPositionZ()); else if (HasUnitMovementFlag(MOVEMENTFLAG_ROOT)) @@ -17541,3 +17543,36 @@ void Unit::SendMovementFeatherFall() BuildMovementPacket(&data); SendMessageToSet(&data, true); } + +void Unit::SendMovementGravityChange() +{ + WorldPacket data(MSG_MOVE_GRAVITY_CHNG, 64); + data.append(GetPackGUID()); + BuildMovementPacket(&data); + SendMessageToSet(&data, true); +} + +void Unit::SendMovementCanFlyChange() +{ + /*! + if ( a3->MoveFlags & MOVEMENTFLAG_CAN_FLY ) + { + v4->MoveFlags |= 0x1000000u; + result = 1; + } + else + { + if ( v4->MoveFlags & MOVEMENTFLAG_FLYING ) + CMovement::DisableFlying(v4); + v4->MoveFlags &= 0xFEFFFFFFu; + result = 1; + } + */ + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->SendMovementSetCanFly(CanFly()); + + WorldPacket data(MSG_MOVE_UPDATE_CAN_FLY, 64); + data.append(GetPackGUID()); + BuildMovementPacket(&data); + SendMessageToSet(&data, true); +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f09bf89a9c7..0e24fdffa9d 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1631,9 +1631,18 @@ class Unit : public WorldObject //void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMonsterMoveTransport(Unit* vehicleOwner); void SendMovementFlagUpdate(); + + /*! These methods send the same packet to the client in apply and unapply case. + The client-side interpretation of this packet depends on the presence of relevant movementflags + which are sent with movementinfo. Furthermore, these packets are broadcast to nearby players as well + as the current unit. + */ void SendMovementHover(); void SendMovementFeatherFall(); void SendMovementWaterWalking(); + void SendMovementGravityChange(); + void SendMovementCanFlyChange(); + bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);} bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);} virtual bool SetWalk(bool enable); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index aaa41ec3519..319cd96c332 100755 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1621,6 +1621,12 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data) recv_data.read_skip<float>(); // unk2 + if (movementInfo.Violated) + { + recv_data.rfinish(); + return; + } + _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); } diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 7d1233c8f70..55c55ffb246 100755 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -278,6 +278,14 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) return; } + //! If some anti-cheat checks in WorldSession::ReadMovementInfo failed, do not process + //! the change of movement server-sided. + if (movementInfo.Violated) + { + recv_data.rfinish(); + return; + } + /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { @@ -485,9 +493,16 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) recv_data.readPackGUID(old_mover_guid); MovementInfo mi; - mi.guid = old_mover_guid; ReadMovementInfo(recv_data, &mi); + if (mi.Violated) + { + recv_data.rfinish(); + return; + } + + mi.guid = old_mover_guid; + _player->m_movementInfo = mi; } @@ -513,6 +528,13 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data) MovementInfo movementInfo; ReadMovementInfo(recv_data, &movementInfo); + + if (movementInfo.Violated) + { + recv_data.rfinish(); + return; + } + _player->m_movementInfo = movementInfo; WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); @@ -571,3 +593,4 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) _player->SummonIfPossible(agree); } +#undef IF_VIOLATED_RETURN
\ No newline at end of file diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp index ce4f6ccb8fe..161571998a1 100644 --- a/src/server/game/Handlers/VehicleHandler.cpp +++ b/src/server/game/Handlers/VehicleHandler.cpp @@ -43,6 +43,12 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) mi.guid = guid; ReadMovementInfo(recv_data, &mi); + if (mi.Violated) + { + recv_data.rfinish(); + return; + } + _player->m_movementInfo = mi; _player->ExitVehicle(); @@ -81,7 +87,16 @@ void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) uint64 guid; // current vehicle guid recv_data.readPackGUID(guid); - ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + + if (movementInfo.Violated) + { + recv_data.rfinish(); + return; + } + + vehicle_base->m_movementInfo = movementInfo; uint64 accessory; // accessory guid recv_data.readPackGUID(accessory); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 775b832d79a..ab6ba7e7796 100755 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1344,7 +1344,7 @@ enum Opcodes CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND = 0x51B, SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C, SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D, - SMSG_COMPRESSED_UNKNOWN_1310 = 0x51E, // some compressed packet? + SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES NUM_MSG_TYPES = 0x51F }; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 84907937de5..6ae9f4f6781 100755 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -807,48 +807,66 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi) if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION)) data >> mi->splineElevation; + //! Anti-cheat checks. Please keep them in seperate if() blocks to maintain a clear overview. + #define VIOLATE_AND_RETURN \ + mi->Violated = true; \ + return; \ + /*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid, and when used in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD it will freeze clients that receive this player's movement info. */ if (mi->HasMovementFlag(MOVEMENTFLAG_ROOT)) - mi->flags &= ~MOVEMENTFLAG_ROOT; + VIOLATE_AND_RETURN; //! Cannot hover and jump at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && mi->HasMovementFlag(MOVEMENTFLAG_JUMPING)) - mi->flags &= ~MOVEMENTFLAG_JUMPING; + VIOLATE_AND_RETURN; //! Cannot ascend and descend at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_ASCENDING) && mi->HasMovementFlag(MOVEMENTFLAG_DESCENDING)) - mi->flags &= ~(MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING); + VIOLATE_AND_RETURN; //! Cannot move left and right at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_RIGHT)) - mi->flags &= ~(MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT); + VIOLATE_AND_RETURN; //! Cannot strafe left and right at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_RIGHT)) - mi->flags &= ~(MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT); + VIOLATE_AND_RETURN; //! Cannot pitch up and down at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_PITCH_UP) && mi->HasMovementFlag(MOVEMENTFLAG_PITCH_DOWN)) - mi->flags &= ~(MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN); + VIOLATE_AND_RETURN; //! Cannot move forwards and backwards at the same time if (mi->HasMovementFlag(MOVEMENTFLAG_FORWARD) && mi->HasMovementFlag(MOVEMENTFLAG_BACKWARD)) - mi->flags &= ~(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD); + VIOLATE_AND_RETURN; //! Cannot walk on water without SPELL_AURA_WATER_WALK if (mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK)) - mi->flags &= ~MOVEMENTFLAG_WATERWALKING; + VIOLATE_AND_RETURN; //! Cannot feather fall without SPELL_AURA_FEATHER_FALL if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) - mi->flags &= ~MOVEMENTFLAG_FALLING_SLOW; + VIOLATE_AND_RETURN; //! Cannot hover without SPELL_AURA_HOVER if (mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER)) - mi->flags &= ~MOVEMENTFLAG_HOVER; + VIOLATE_AND_RETURN; + + /*! Cannot fly if no fly auras present. Exception is being a GM. + Note that we check for account level instead of Player::IsGameMaster() because in some + situations it may be feasable to use .gm fly on as a GM without having .gm on, + e.g. aerial combat. + */ + + if (mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && + !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && + !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) + VIOLATE_AND_RETURN; + + #undef VIOLATE_AND_RETURN } void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index ddef7fdd749..1e0d1e3b08d 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2844,21 +2844,14 @@ void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode return; } - if (target->GetTypeId() == TYPEID_UNIT) - target->SetCanFly(apply); + //! Not entirely sure if this should be sent for creatures as well, but I don't think so. + target->SetCanFly(apply); + Player* player = target->ToPlayer(); + if (!player) + player = target->m_movedPlayer; - if (Player* player = target->m_movedPlayer) - { - // allow flying - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); - else - data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); - data.append(target->GetPackGUID()); - data << uint32(0); // movement counter - player->SendDirectMessage(&data); - } + if (player) + player->SendMovementCanFlyChange(); } void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3231,25 +3224,22 @@ void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, Unit* target = aurApp->GetTarget(); - // Enable Fly mode for flying mounts + //! Update ability to fly if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK && (apply || (!target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !target->HasAuraType(SPELL_AURA_FLY)))) { - if (Player* player = target->m_movedPlayer) - { - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); - else - data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); - data.append(player->GetPackGUID()); - data << uint32(0); // unknown - player->SendDirectMessage(&data); - } + target->SetCanFly(apply); + Player* player = target->ToPlayer(); + if (!player) + player = target->m_movedPlayer; + + if (player) + player->SendMovementCanFlyChange(); } + //! Someone should clean up these hacks and remove it from this function. It doesn't even belong here. if (mode & AURA_EFFECT_HANDLE_REAL) { //Players on flying mounts must be immune to polymorph diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0b05db07d38..21d49ccf151 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4956,10 +4956,11 @@ SpellCastResult Spell::CheckCast(bool strict) return castResult; bool hasDispellableAura = false; + bool hasNonDispelEffect = false; for (int i = 0; i < MAX_SPELL_EFFECTS; i++) if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL) { - if (m_spellInfo->Effects[i].IsTargetingArea()) + if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START) { hasDispellableAura = true; break; @@ -4976,8 +4977,13 @@ SpellCastResult Spell::CheckCast(bool strict) } } } + else if (m_spellInfo->Effects[i].IsEffect()) + { + hasNonDispelEffect = true; + break; + } - if (!hasDispellableAura && m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) + if (!hasNonDispelEffect && !hasDispellableAura && m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) return SPELL_FAILED_NOTHING_TO_DISPEL; for (int i = 0; i < MAX_SPELL_EFFECTS; i++) |
