diff options
Diffstat (limited to 'src/server/game')
19 files changed, 359 insertions, 56 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 5957eeefd7e..97fe3b80f10 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3461,16 +3461,10 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at) void SmartScript::OnMoveInLineOfSight(Unit* who) { - ProcessEventsFor(SMART_EVENT_OOC_LOS, who); - if (!me) return; - if (me->GetVictim()) - return; - - ProcessEventsFor(SMART_EVENT_IC_LOS, who); - + ProcessEventsFor(me->IsInCombat() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who); } /* diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index a136ed8a438..a797f6109ca 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -55,7 +55,7 @@ Battlefield::Battlefield() m_uiKickAfkPlayersTimer = 1000; - m_LastResurectTimer = 30 * IN_MILLISECONDS; + m_LastResurrectTimer = 30 * IN_MILLISECONDS; m_StartGroupingTimer = 0; m_StartGrouping = false; StalkerGuid = 0; @@ -185,15 +185,15 @@ bool Battlefield::Update(uint32 diff) } - if (m_LastResurectTimer <= diff) + if (m_LastResurrectTimer <= diff) { for (uint8 i = 0; i < m_GraveyardList.size(); i++) if (GetGraveyardById(i)) m_GraveyardList[i]->Resurrect(); - m_LastResurectTimer = RESURRECTION_INTERVAL; + m_LastResurrectTimer = RESURRECTION_INTERVAL; } else - m_LastResurectTimer -= diff; + m_LastResurrectTimer -= diff; return objective_changed; } @@ -634,7 +634,7 @@ void Battlefield::RemovePlayerFromResurrectQueue(uint64 playerGuid) void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, uint64 guid) { WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time = m_LastResurectTimer; // resurrect every 30 seconds + uint32 time = m_LastResurrectTimer; // resurrect every 30 seconds data << guid << time; ASSERT(player && player->GetSession()); @@ -713,7 +713,7 @@ void BfGraveyard::Resurrect() if (Creature* spirit = m_Bf->GetCreature(m_SpiritGuide[m_ControlTeam])) spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true); - // Resurect player + // Resurrect player player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true); player->ResurrectPlayer(1.0f); player->CastSpell(player, 6962, true); diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 4e2e28f124c..1b142d1c89f 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -174,7 +174,7 @@ class BfGraveyard // Check if this graveyard has a spirit guide bool HasNpc(uint64 guid); - // Check if a player is in this graveyard's ressurect queue + // Check if a player is in this graveyard's resurrect queue bool HasPlayer(uint64 guid) { return m_ResurrectQueue.find(guid) != m_ResurrectQueue.end(); } // Get the graveyard's ID. @@ -387,7 +387,7 @@ class Battlefield : public ZoneScript // Graveyard variables GraveyardVect m_GraveyardList; // Vector witch contain the different GY of the battle - uint32 m_LastResurectTimer; // Timer for resurect player every 30 sec + uint32 m_LastResurrectTimer; // Timer for resurrect player every 30 sec uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle bool m_StartGrouping; // bool for know if all players in area has been invited diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 24e01cf5b37..dff99280e73 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -273,7 +273,7 @@ void Battleground::Update(uint32 diff) } else { - _ProcessRessurect(diff); + _ProcessResurrect(diff); if (sBattlegroundMgr->GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) _ProcessProgress(diff); else if (m_PrematureCountDown) @@ -342,10 +342,10 @@ inline void Battleground::_ProcessOfflineQueue() } } -inline void Battleground::_ProcessRessurect(uint32 diff) +inline void Battleground::_ProcessResurrect(uint32 diff) { // ********************************************************* - // *** BATTLEGROUND RESSURECTION SYSTEM *** + // *** BATTLEGROUND RESURRECTION SYSTEM *** // ********************************************************* // this should be handled by spell system m_LastResurrectTime += diff; diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 2feb15e2ee6..205d03c1e61 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -561,7 +561,7 @@ class Battleground Player* _GetPlayerForTeam(uint32 teamId, BattlegroundPlayerMap::const_iterator itr, const char* context) const; void _ProcessOfflineQueue(); - void _ProcessRessurect(uint32 diff); + void _ProcessResurrect(uint32 diff); void _ProcessProgress(uint32 diff); void _ProcessLeave(uint32 diff); void _ProcessJoin(uint32 diff); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 9ad6877d929..115e340762e 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -25,7 +25,7 @@ #include "Common.h" -#include "Opcodes.h" +#include "WorldSession.h" #include "WorldPacket.h" class Player; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d9304752e73..d6a029d29bf 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2014,6 +2014,10 @@ void GameObject::SetLootState(LootState state, Unit* unit) m_lootStateUnitGUID = unit ? unit->GetGUID() : 0; AI()->OnStateChanged(state, unit); sScriptMgr->OnGameObjectLootStateChanged(this, state, unit); + + if (GetGoType() == GAMEOBJECT_TYPE_DOOR) // only set collision for doors on SetGoState + return; + if (m_model) { bool collision = false; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a8434bb515e..f5c6d12a341 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7804,6 +7804,19 @@ void Player::UpdateArea(uint32 newArea) else RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); + uint32 const areaRestFlag = (GetTeam() == ALLIANCE) ? AREA_FLAG_REST_ZONE_ALLIANCE : AREA_FLAG_REST_ZONE_HORDE; + if (area && area->flags & areaRestFlag) + { + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_IN_FACTION_AREA); + InnEnter(time(0), GetMapId(), 0, 0, 0); + } + else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && GetRestType() == REST_TYPE_IN_FACTION_AREA) + { + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_NO); + } + phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); } @@ -7892,8 +7905,9 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) SetRestType(REST_TYPE_NO); } } - else // Recently left a capital city + else if (GetRestType() != REST_TYPE_IN_FACTION_AREA) // handled in UpdateArea { + // Recently left a capital city RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); SetRestType(REST_TYPE_NO); } @@ -8490,7 +8504,12 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType att { HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply); if (unitModType == TOTAL_VALUE) - ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); + { + if (aura->GetAmount() > 0) + ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); + else + ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply); + } } } @@ -22684,7 +22703,7 @@ void Player::UpdatePotionCooldown(Spell* spell) void Player::SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura) { - ASSERT(!IsRessurectRequested()); + ASSERT(!IsResurrectRequested()); _resurrectionData = new ResurrectionData(); _resurrectionData->GUID = caster->GetGUID(); _resurrectionData->Location.WorldRelocate(*caster); @@ -24520,7 +24539,7 @@ bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE); } -void Player::ResurectUsingRequestData() +void Player::ResurrectUsingRequestData() { /// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse float x, y, z, o; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2f210b5f9f8..dccbc550a1e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -802,9 +802,10 @@ class InstanceSave; enum RestType { - REST_TYPE_NO = 0, - REST_TYPE_IN_TAVERN = 1, - REST_TYPE_IN_CITY = 2 + REST_TYPE_NO = 0, + REST_TYPE_IN_TAVERN = 1, + REST_TYPE_IN_CITY = 2, + REST_TYPE_IN_FACTION_AREA = 3 // used with AREA_FLAG_REST_ZONE_* }; enum TeleportToOptions @@ -1869,16 +1870,16 @@ class Player : public Unit, public GridObject<Player> _resurrectionData = NULL; } - bool IsRessurectRequestedBy(uint64 guid) const + bool IsResurrectRequestedBy(uint64 guid) const { - if (!IsRessurectRequested()) + if (!IsResurrectRequested()) return false; return _resurrectionData->GUID == guid; } - bool IsRessurectRequested() const { return _resurrectionData != NULL; } - void ResurectUsingRequestData(); + bool IsResurrectRequested() const { return _resurrectionData != NULL; } + void ResurrectUsingRequestData(); uint8 getCinematic() { return m_cinematic; } void setCinematic(uint8 cine) { m_cinematic = cine; } diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index f505c8dd64d..6e593951f2c 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -19,7 +19,7 @@ #include "SocialMgr.h" #include "DatabaseEnv.h" -#include "Opcodes.h" +#include "WorldSession.h" #include "WorldPacket.h" #include "Player.h" #include "ObjectMgr.h" diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 866a99bcfb7..e57c748b540 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -187,11 +187,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_WHO Message"); - time_t now = time(NULL); - if (now - timeLastWhoCommand < 5) - return; - else timeLastWhoCommand = now; - uint32 matchcount = 0; uint32 level_min, level_max, racemask, classmask, zones_count, str_count; @@ -795,10 +790,10 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData) return; } - if (!GetPlayer()->IsRessurectRequestedBy(guid)) + if (!GetPlayer()->IsResurrectRequestedBy(guid)) return; - GetPlayer()->ResurectUsingRequestData(); + GetPlayer()->ResurrectUsingRequestData(); } void WorldSession::SendAreaTriggerMessage(const char* Text, ...) diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index cbb76ba4612..97834d3e444 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1232,6 +1232,8 @@ enum TrinityStrings LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, + LANG_NPCINFO_INHABIT_TYPE = 11008 + // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) // For other tables maybe 2000010000-2147483647 (max index) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index cd57789ed60..89ddb6697e3 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1282,7 +1282,7 @@ enum SpellCustomErrors SPELL_CUSTOM_ERROR_REQUIRES_CONTROL_FIREWORKS = 95, // Requires Remote Control Fireworks. Return to Hobart Grapplehammer to get more. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_RECRUITS = 96, // You already have the max number of recruits. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_VOLUNTEERS = 97, // You already have the max number of volunteers. - SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESSURECT = 98, // Frostmourne has rendered you unable to ressurect. + SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESURRECT = 98, // Frostmourne has rendered you unable to resurrect. SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99, // You can't mount while affected by that shapeshift. SPELL_CUSTOM_ERROR_FAWNS_ALREADY_FOLLOWING = 100, // Three fawns are already following you! SPELL_CUSTOM_ERROR_ALREADY_HAVE_RIVER_BOAT = 101, // You already have a River Boat. diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 8f77f09ba2d..94bfc8e1305 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1395,11 +1395,18 @@ enum PacketProcessing PROCESS_THREADSAFE //packet is thread-safe - process it in Map::Update() }; +class WorldSession; class WorldPacket; class WorldSession; typedef void(WorldSession::*pOpcodeHandler)(WorldPacket& recvPacket); +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + struct OpcodeHandler { OpcodeHandler() {} @@ -1446,6 +1453,12 @@ class OpcodeTable extern OpcodeTable opcodeTable; +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + void InitOpcodes(); /// Lookup opcode name for human understandable logging diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index a99695206ad..a16af561125 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -124,7 +124,6 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 _filterAddonMessages(false), recruiterId(recruiter), isRecruiter(isARecruiter), - timeLastWhoCommand(0), _RBACData(NULL) { memset(m_Tutorials, 0, sizeof(m_Tutorials)); @@ -317,12 +316,13 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. uint32 processedPackets = 0; + time_t currentTime = time(NULL); while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { - if (!AntiDOS.EvaluateOpcode(*packet)) + if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) KickPlayer(); OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()]; @@ -1176,14 +1176,38 @@ void WorldSession::InvalidateRBACData() _RBACData = NULL; } -bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p) const +bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) const { - if (IsOpcodeAllowed(p.GetOpcode())) - return true; + PacketCounter& packetCounter = _PacketThrottlingMap[p.GetOpcode()]; + if (packetCounter.lastReceiveTime != time) + { + packetCounter.lastReceiveTime = time; + packetCounter.amountCounter = 0; + } + + uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode()); + + bool dosTriggered = false; + // Check if player is flooding some packets + if (++packetCounter.amountCounter > maxPacketCounterAllowed) + { + dosTriggered = true; + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, flooding packet (opc: %s, count: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), packetCounter.amountCounter); + } + + // Then check if player is sending packets not allowed + if (!IsOpcodeAllowed(p.GetOpcode())) + { + dosTriggered = true; + // Opcode not allowed, let the punishment begin + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size()); + } - // Opcode not allowed, let the punishment begin - TC_LOG_INFO("network", "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)", - Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size()); + // Return true if everything is fine, otherwise apply the configured policy + if (!dosTriggered) + return true; switch (_policy) { @@ -1212,3 +1236,234 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p) const return true; } } + + +uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) const +{ + uint32 maxPacketCounterAllowed; + switch (opcode) + { + case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: + case CMSG_MESSAGECHAT_ADDON_GUILD: + case CMSG_MESSAGECHAT_ADDON_OFFICER: + case CMSG_MESSAGECHAT_ADDON_PARTY: + case CMSG_MESSAGECHAT_ADDON_RAID: + case CMSG_MESSAGECHAT_ADDON_WHISPER: + case CMSG_MESSAGECHAT_AFK: + case CMSG_MESSAGECHAT_BATTLEGROUND: + case CMSG_MESSAGECHAT_CHANNEL: + case CMSG_MESSAGECHAT_DND: + case CMSG_MESSAGECHAT_EMOTE: + case CMSG_MESSAGECHAT_GUILD: + case CMSG_MESSAGECHAT_OFFICER: + case CMSG_MESSAGECHAT_PARTY: + case CMSG_MESSAGECHAT_RAID: + case CMSG_MESSAGECHAT_RAID_WARNING: + case CMSG_MESSAGECHAT_SAY: + case CMSG_MESSAGECHAT_WHISPER: + case CMSG_MESSAGECHAT_YELL: + { + maxPacketCounterAllowed = 500; + break; + } + + case CMSG_ATTACKSTOP: + case CMSG_GUILD_QUERY: + case CMSG_NAME_QUERY: + case CMSG_PET_NAME_QUERY: + case CMSG_GAMEOBJECT_QUERY: + case CMSG_CREATURE_QUERY: + case CMSG_NPC_TEXT_QUERY: + case CMSG_ARENA_TEAM_QUERY: + case CMSG_TAXINODE_STATUS_QUERY: + case CMSG_TAXIQUERYAVAILABLENODES: + case CMSG_QUESTGIVER_QUERY_QUEST: + case CMSG_QUEST_QUERY: + case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: + case CMSG_QUERY_QUESTS_COMPLETED: + case CMSG_QUEST_POI_QUERY: + case CMSG_QUERY_TIME: + case CMSG_PAGE_TEXT_QUERY: + case CMSG_PETITION_QUERY: + case CMSG_QUERY_INSPECT_ACHIEVEMENTS: + case CMSG_AREA_SPIRIT_HEALER_QUERY: + case CMSG_CORPSE_MAP_POSITION_QUERY: + case CMSG_MOVE_TIME_SKIPPED: + case CMSG_GUILD_BANK_QUERY_TAB: + case CMSG_GUILD_BANK_LOG_QUERY: + case CMSG_GUILD_EVENT_LOG_QUERY: + case MSG_CORPSE_QUERY: + case MSG_QUERY_NEXT_MAIL_TIME: + case MSG_MOVE_SET_FACING: + { + maxPacketCounterAllowed = 200; + break; + } + + case CMSG_REQUEST_PARTY_MEMBER_STATS: + case CMSG_WHO: + { + maxPacketCounterAllowed = 50; + break; + } + + case CMSG_SETSHEATHED: + case CMSG_CONTACT_LIST: + { + maxPacketCounterAllowed = 10; + break; + } + + case CMSG_GAMEOBJ_USE: + case CMSG_GAMEOBJ_REPORT_USE: + case CMSG_SPELLCLICK: + case CMSG_PLAYER_LOGOUT: + case CMSG_LOGOUT_REQUEST: + case CMSG_LOGOUT_CANCEL: + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: + case CMSG_REQUEST_VEHICLE_PREV_SEAT: + case CMSG_REQUEST_VEHICLE_NEXT_SEAT: + case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: + case CMSG_TOGGLE_PVP: + case CMSG_ADD_FRIEND: + case CMSG_DEL_FRIEND: + case CMSG_SET_CONTACT_NOTES: + case CMSG_RESET_INSTANCES: + case CMSG_HEARTH_AND_RESURRECT: + case CMSG_CHAR_CREATE: + case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: + case CMSG_CHAR_ENUM: + case CMSG_REALM_SPLIT: + case CMSG_CHAR_DELETE: + case CMSG_PLAYER_LOGIN: + case CMSG_PET_ABANDON: + case CMSG_PET_RENAME: + case CMSG_CHAR_RENAME: + case CMSG_CHAR_CUSTOMIZE: + case CMSG_CHAR_RACE_CHANGE: + case CMSG_CHAR_FACTION_CHANGE: + case CMSG_GMTICKET_CREATE: + case CMSG_GMTICKET_UPDATETEXT: + case CMSG_GMTICKET_DELETETICKET: + case CMSG_GMSURVEY_SUBMIT: + case CMSG_GM_REPORT_LAG: + case CMSG_BUG: + case CMSG_GMRESPONSE_RESOLVE: + case CMSG_ACTIVATETAXIEXPRESS: + case CMSG_ACTIVATETAXI: + case CMSG_SELF_RES: + case CMSG_INITIATE_TRADE: + case CMSG_BEGIN_TRADE: + case CMSG_UNLEARN_SKILL: + case CMSG_DISMISS_CONTROLLED_VEHICLE: + case CMSG_REQUEST_VEHICLE_EXIT: + case CMSG_LEARN_PREVIEW_TALENTS: + case CMSG_LEARN_PREVIEW_TALENTS_PET: + case CMSG_PLAYER_VEHICLE_ENTER: + case CMSG_EJECT_PASSENGER: + case CMSG_EQUIPMENT_SET_SAVE: + case CMSG_EQUIPMENT_SET_DELETE: + case CMSG_ALTER_APPEARANCE: + case CMSG_QUESTGIVER_ACCEPT_QUEST: + case CMSG_QUESTGIVER_CHOOSE_REWARD: + case CMSG_QUESTGIVER_REQUEST_REWARD: + //case CMSG_QUESTGIVER_CANCEL: + case CMSG_QUESTLOG_REMOVE_QUEST: + case CMSG_QUEST_CONFIRM_ACCEPT: + case CMSG_QUESTGIVER_COMPLETE_QUEST: + case CMSG_DISMISS_CRITTER: + case CMSG_REPOP_REQUEST: + case CMSG_PETITION_BUY: + case CMSG_PETITION_SIGN: + case CMSG_TURN_IN_PETITION: + case CMSG_COMPLETE_CINEMATIC: + case CMSG_ITEM_REFUND: + case CMSG_SOCKET_GEMS: + case CMSG_WRAP_ITEM: + case CMSG_BUY_BANK_SLOT: + case CMSG_GROUP_INVITE_RESPONSE: + //case CMSG_GROUP_UNINVITE: + case CMSG_GROUP_UNINVITE_GUID: + case CMSG_GROUP_SET_LEADER: + case CMSG_GROUP_DISBAND: + case CMSG_GROUP_RAID_CONVERT: + case CMSG_GROUP_CHANGE_SUB_GROUP: + case CMSG_GROUP_ASSISTANT_LEADER: + case CMSG_OPT_OUT_OF_LOOT: + case CMSG_BATTLEMASTER_JOIN_ARENA: + case CMSG_BATTLEFIELD_LEAVE: + case CMSG_REPORT_PVP_AFK: + case CMSG_DUEL_ACCEPTED: + case CMSG_DUEL_CANCELLED: + case CMSG_CALENDAR_GET_CALENDAR: + case CMSG_CALENDAR_ADD_EVENT: + case CMSG_CALENDAR_UPDATE_EVENT: + case CMSG_CALENDAR_REMOVE_EVENT: + case CMSG_CALENDAR_COPY_EVENT: + case CMSG_CALENDAR_EVENT_INVITE: + case CMSG_CALENDAR_EVENT_SIGNUP: + case CMSG_CALENDAR_EVENT_RSVP: + case CMSG_CALENDAR_EVENT_REMOVE_INVITE: + case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: + case CMSG_CALENDAR_COMPLAIN: + case CMSG_ARENA_TEAM_INVITE: + case CMSG_ARENA_TEAM_ACCEPT: + case CMSG_ARENA_TEAM_DECLINE: + case CMSG_ARENA_TEAM_LEAVE: + case CMSG_ARENA_TEAM_DISBAND: + case CMSG_ARENA_TEAM_REMOVE: + case CMSG_ARENA_TEAM_LEADER: + case CMSG_LOOT_METHOD: + case CMSG_GUILD_INVITE: + case CMSG_GUILD_ACCEPT: + case CMSG_GUILD_DECLINE: + case CMSG_GUILD_LEAVE: + case CMSG_GUILD_DISBAND: + case CMSG_GUILD_SET_GUILD_MASTER: + case CMSG_GUILD_MOTD: + case SMSG_GUILD_NEWS_UPDATE: + case CMSG_GUILD_QUERY_RANKS: + case CMSG_GUILD_ADD_RANK: + case CMSG_GUILD_DEL_RANK: + case CMSG_GUILD_INFO_TEXT: + case CMSG_GUILD_BANK_DEPOSIT_MONEY: + case CMSG_GUILD_BANK_WITHDRAW_MONEY: + case CMSG_GUILD_BANK_BUY_TAB: + case CMSG_GUILD_BANK_UPDATE_TAB: + case CMSG_SET_GUILD_BANK_TEXT: + case MSG_SAVE_GUILD_EMBLEM: + case MSG_PETITION_RENAME: + case MSG_PETITION_DECLINE: + case MSG_TALENT_WIPE_CONFIRM: + case MSG_SET_DUNGEON_DIFFICULTY: + case MSG_SET_RAID_DIFFICULTY: + case MSG_RANDOM_ROLL: + case MSG_RAID_TARGET_UPDATE: + case MSG_PARTY_ASSIGNMENT: + case MSG_RAID_READY_CHECK: + { + maxPacketCounterAllowed = 3; + break; + } + + case CMSG_SET_ACTION_BUTTON: + { + maxPacketCounterAllowed = MAX_ACTION_BUTTONS; + break; + } + + case CMSG_ITEM_REFUND_INFO: + { + maxPacketCounterAllowed = PLAYER_SLOTS_COUNT; + break; + } + + default: + { + maxPacketCounterAllowed = 100; + break; + } + } + + return maxPacketCounterAllowed; +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 2453104c80e..3a3a2730c2d 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -28,6 +28,7 @@ #include "AddonMgr.h" #include "DatabaseEnv.h" #include "World.h" +#include "Opcodes.h" #include "WorldPacket.h" #include "Cryptography/BigNumber.h" #include "Opcodes.h" @@ -203,6 +204,12 @@ class CharacterCreateInfo uint8 CharCount; }; +struct PacketCounter +{ + time_t lastReceiveTime; + uint32 amountCounter; +}; + /// Player session in the World class WorldSession { @@ -985,7 +992,7 @@ class WorldSession friend class World; public: DosProtection(WorldSession* s) : Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) { } - bool EvaluateOpcode(WorldPacket& p) const; + bool EvaluateOpcode(WorldPacket& p, time_t time) const; void AllowOpcode(uint16 opcode, bool allow) { _isOpcodeAllowed[opcode] = allow; } protected: enum Policy @@ -1004,12 +1011,17 @@ class WorldSession return itr->second; } + uint32 GetMaxPacketCounterAllowed(uint16 opcode) const; + WorldSession* Session; private: typedef std::unordered_map<uint16, bool> OpcodeStatusMap; OpcodeStatusMap _isOpcodeAllowed; // could be bool array, but wouldn't be practical for game versions with non-linear opcodes Policy _policy; + typedef std::unordered_map<uint16, PacketCounter> PacketThrottlingMap; + // mark this member as "mutable" so it can be modified even in const functions + mutable PacketThrottlingMap _PacketThrottlingMap; DosProtection(DosProtection const& right) = delete; DosProtection& operator=(DosProtection const& right) = delete; @@ -1066,7 +1078,6 @@ class WorldSession uint32 recruiterId; bool isRecruiter; ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; - time_t timeLastWhoCommand; z_stream_s* _compressionStream; rbac::RBACData* _RBACData; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c2876a2536e..661c1ec340a 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4223,7 +4223,7 @@ void Spell::SendChannelStart(uint32 duration) void Spell::SendResurrectRequest(Player* target) { - // get ressurector name for creature resurrections, otherwise packet will be not accepted + // get resurrector name for creature resurrections, otherwise packet will be not accepted // for player resurrections the name is looked up by guid std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER ? "" diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9c6b69ef7d7..8dfa017467a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -280,7 +280,7 @@ void Spell::EffectResurrectNew(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = damage; @@ -4254,7 +4254,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); @@ -5713,7 +5713,7 @@ void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) if (unitTarget->IsAlive()) return; - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ef9e6d5aa21..7491920c36a 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -24,6 +24,7 @@ #include "Player.h" #include "Battleground.h" #include "Vehicle.h" +#include "Pet.h" uint32 GetTargetFlagMask(SpellTargetObjectTypes objType) { @@ -1678,8 +1679,16 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta // creature/player specific target checks if (unitTarget) { - if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && unitTarget->IsInCombat()) - return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT) + { + if (unitTarget->IsInCombat()) + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + // player with active pet counts as a player in combat + else if (Player const* player = unitTarget->ToPlayer()) + if (Pet* pet = player->GetPet()) + if (pet->GetVictim() && !pet->HasUnitState(UNIT_STATE_CONTROLLED)) + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + } // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST)) |
