diff --git a/apps/ci/ci-install-modules.sh b/apps/ci/ci-install-modules.sh
index 5e98469c7..b3271de3c 100755
--- a/apps/ci/ci-install-modules.sh
+++ b/apps/ci/ci-install-modules.sh
@@ -28,3 +28,4 @@ git clone --depth=1 --branch=master https://github.com/azerothcore/mod-server-au
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-transmog.git modules/mod-transmog
git clone --depth=1 --branch=main https://github.com/azerothcore/mod-progression-system.git modules/mod-progression-system
git clone --depth=1 --branch=master https://github.com/azerothcore/mod-arena-3v3-solo-queue.git modules/mod-arena-3v3-solo-queue
+git clone --depth=1 --branch=master https://github.com/azerothcore/mod-costumes.git modules/mod-costumes
diff --git a/data/sql/updates/db_world/2025_02_19_01.sql b/data/sql/updates/db_world/2025_02_19_01.sql
new file mode 100644
index 000000000..6e2dfd8f9
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_19_01.sql
@@ -0,0 +1,36 @@
+-- DB update 2025_02_19_00 -> 2025_02_19_01
+-- Bjorn Halgurdsson - Set position
+UPDATE `creature` SET `position_x` = 1518.61, `position_y` = -5249.85, `position_z` = 215.38, `orientation` = 5.41052, `VerifiedBuild` = 59069 WHERE `guid` = 112513 AND `id1` = 24238;
+
+-- Bjorn Halgurdsson - Set speed_run
+UPDATE `creature_template` SET `speed_run` = 1.7435 WHERE (`entry` = 24238);
+
+-- Bjorn Halgurdsson - Set mount
+DELETE FROM `creature_addon` WHERE (`guid` IN (112513));
+INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
+(112513, 0, 22657, 0, 0, 0, 0, NULL);
+
+-- Bjorn Halgurdsson - Set movement
+UPDATE `creature_template_movement` SET `Swim` = 0, `Flight` = 0 WHERE (`CreatureId` = 24238);
+
+-- Bjorn Halgurdsson - SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 24238;
+
+DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24238);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(24238, 0, 0, 0, 1, 0, 100, 0, 10000, 15000, 45000, 60000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - Out of Combat - Say Line 2'),
+(24238, 0, 1, 2, 8, 0, 100, 0, 43315, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Say Line 0'),
+(24238, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Say Line 1'),
+(24238, 0, 3, 4, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Dismount'),
+(24238, 0, 4, 5, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Set hover 0'),
+(24238, 0, 5, 6, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Set Fly Off'),
+(24238, 0, 6, 7, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Set Reactstate Aggressive'),
+(24238, 0, 7, 8, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Remove Flags Not Attackable'),
+(24238, 0, 8, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Spellhit \'Vrykul Insult\' - Start Attacking'),
+(24238, 0, 9, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 43371, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Just Died - Cast \'Bjorn Kill Credit\''),
+(24238, 0, 10, 0, 0, 0, 100, 0, 5000, 10000, 10000, 15000, 0, 0, 11, 32736, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - In Combat - Cast \'Mortal Strike\''),
+(24238, 0, 11, 0, 0, 0, 100, 0, 0, 5000, 10000, 15000, 0, 0, 11, 33661, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - In Combat - Cast \'Crush Armor\''),
+(24238, 0, 12, 13, 25, 0, 100, 512, 0, 0, 0, 0, 0, 0, 60, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Reset - Set Fly On'),
+(24238, 0, 13, 14, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Reset - Set hover 1'),
+(24238, 0, 14, 15, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Reset - Set Reactstate Passive'),
+(24238, 0, 15, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 18, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bjorn Halgurdsson - On Reset - Set Flags Not Attackable');
diff --git a/data/sql/updates/db_world/2025_02_21_00.sql b/data/sql/updates/db_world/2025_02_21_00.sql
new file mode 100644
index 000000000..86fb9a021
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_21_00.sql
@@ -0,0 +1,112 @@
+-- DB update 2025_02_19_01 -> 2025_02_21_00
+DROP TABLE IF EXISTS `antidos_opcode_policies`;
+CREATE TABLE `antidos_opcode_policies` (
+ `Opcode` smallint unsigned NOT NULL,
+ `Policy` tinyint unsigned NOT NULL,
+ `MaxAllowedCount` smallint unsigned NOT NULL,
+ PRIMARY KEY (`Opcode`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+INSERT INTO `antidos_opcode_policies` (`Opcode`, `Policy`, `MaxAllowedCount`) VALUES
+ (393, 1, 200),
+ (404, 1, 200),
+ (398, 1, 200),
+ (102, 1, 200),
+ (1217, 1, 200),
+ (643, 1, 200),
+ (642, 1, 200),
+ (98, 1, 200),
+ (1192, 1, 200),
+ (1218, 1, 200),
+ (238, 1, 200),
+ (564, 1, 50),
+ (565, 1, 50),
+ (107, 1, 50),
+ (1065, 1, 50),
+ (999, 1, 50),
+ (1131, 1, 50),
+ (1153, 1, 50),
+ (177, 1, 50),
+ (450, 1, 50),
+ (483, 1, 25),
+ (1282, 1, 20),
+ (1016, 1, 20),
+ (1162, 1, 20),
+ (1133, 1, 20),
+ (448, 1, 10),
+ (452, 1, 10),
+ (638, 1, 10),
+ (454, 1, 10),
+ (1272, 1, 10),
+ (1139, 1, 10),
+ (1241, 1, 10),
+ (56, 1, 10),
+ (106, 1, 10),
+ (105, 1, 10),
+ (711, 1, 10),
+ (810, 1, 10),
+ (458, 1, 10),
+ (120, 1, 10),
+ (654, 1, 10),
+ (655, 1, 10),
+ (445, 1, 10),
+ (1179, 1, 10),
+ (1143, 1, 10),
+ (1144, 1, 10),
+ (1145, 1, 10),
+ (1142, 1, 10),
+ (1193, 1, 10),
+ (1204, 1, 10),
+ (839, 1, 10),
+ (467, 1, 10),
+ (996, 1, 10),
+ (600, 4, 5),
+ (612, 4, 5),
+ (601, 4, 5),
+ (54, 1, 3),
+ (55, 1, 3),
+ (517, 1, 3),
+ (519, 1, 3),
+ (535, 1, 3),
+ (1264, 1, 3),
+ (1069, 1, 3),
+ (1070, 1, 3),
+ (1071, 1, 3),
+ (1072, 1, 3),
+ (1073, 1, 3),
+ (1210, 1, 3),
+ (1074, 1, 3),
+ (1075, 1, 3),
+ (1077, 1, 3),
+ (847, 1, 3),
+ (849, 1, 3),
+ (850, 1, 3),
+ (851, 1, 3),
+ (853, 1, 3),
+ (852, 1, 3),
+ (854, 1, 3),
+ (122, 1, 3),
+ (130, 1, 3),
+ (132, 1, 3),
+ (133, 1, 3),
+ (141, 1, 3),
+ (143, 1, 3),
+ (144, 1, 3),
+ (145, 1, 3),
+ (561, 1, 3),
+ (562, 1, 3),
+ (563, 1, 3),
+ (764, 1, 3),
+ (1004, 1, 3),
+ (1005, 1, 3),
+ (1002, 1, 3),
+ (1003, 1, 3),
+ (1035, 1, 3),
+ (497, 1, 3),
+ (705, 1, 3),
+ (682, 1, 3),
+ (809, 1, 3),
+ (1259, 1, 3),
+ (910, 1, 3),
+ (802, 1, 3),
+ (1203, 1, 150);
diff --git a/data/sql/updates/db_world/2025_02_21_01.sql b/data/sql/updates/db_world/2025_02_21_01.sql
new file mode 100644
index 000000000..808e316c7
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_21_01.sql
@@ -0,0 +1,8 @@
+-- DB update 2025_02_21_00 -> 2025_02_21_01
+--
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN
+('spell_eredar_twins_handle_dark_touched_periodic', 'spell_eredar_twins_handle_flame_touched_periodic', 'spell_eredar_twins_handle_flame_touched_flame_sear');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(45342, 'spell_eredar_twins_handle_flame_touched_periodic'),
+(45271, 'spell_eredar_twins_handle_dark_touched_periodic'),
+(46771, 'spell_eredar_twins_handle_flame_touched_flame_sear');
diff --git a/data/sql/updates/db_world/2025_02_21_02.sql b/data/sql/updates/db_world/2025_02_21_02.sql
new file mode 100644
index 000000000..d71febcdd
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_21_02.sql
@@ -0,0 +1,5 @@
+-- DB update 2025_02_21_01 -> 2025_02_21_02
+--
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24666) AND (`source_type` = 0) AND (`id` IN (4));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(24666, 0, 4, 0, 37, 0, 100, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flame Strike Trigger (Kael - 5Man) - On Initialize - Set Reactstate Passive');
diff --git a/data/sql/updates/db_world/2025_02_21_03.sql b/data/sql/updates/db_world/2025_02_21_03.sql
new file mode 100644
index 000000000..f0152a476
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_21_03.sql
@@ -0,0 +1,4 @@
+-- DB update 2025_02_21_02 -> 2025_02_21_03
+--
+UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = 120 WHERE (`creature_id` = 24664);
+UPDATE `creature_onkill_reputation` SET `MaxStanding1` = 7 WHERE `creature_id` IN (24723, 24560, 24664, 24744);
diff --git a/data/sql/updates/db_world/2025_02_22_00.sql b/data/sql/updates/db_world/2025_02_22_00.sql
new file mode 100644
index 000000000..754270606
--- /dev/null
+++ b/data/sql/updates/db_world/2025_02_22_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2025_02_21_03 -> 2025_02_22_00
+--
+UPDATE `creature_template_movement` SET `Flight` = 2 WHERE `CreatureId` = 24418;
diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist
index 98cbc3970..17fd68060 100644
--- a/src/server/apps/worldserver/worldserver.conf.dist
+++ b/src/server/apps/worldserver/worldserver.conf.dist
@@ -1120,17 +1120,6 @@ PreventAFKLogout = 0
###################################################################################################
# PACKET SPOOF PROTECTION SETTINGS
-#
-# These settings determine which action to take when harmful packet spoofing is detected.
-#
-# PacketSpoof.Policy
-# Description: Determines the course of action when packet spoofing is detected.
-# Values: 0 - Log only
-# 1 - Log + kick
-# 2 - Log + kick + ban
-
-PacketSpoof.Policy = 1
-
#
# PacketSpoof.BanMode
# Description: If PacketSpoof.Policy equals 2, this will determine the ban mode.
diff --git a/src/server/game/Globals/WorldGlobals.cpp b/src/server/game/Globals/WorldGlobals.cpp
new file mode 100644
index 000000000..fcfb3369e
--- /dev/null
+++ b/src/server/game/Globals/WorldGlobals.cpp
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the AzerothCore 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 Affero General Public License as published by the
+ * Free Software Foundation; either version 3 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 Affero 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 .
+ */
+
+#include "DatabaseEnv.h"
+#include "Log.h"
+#include "QueryResult.h"
+#include "Timer.h"
+#include "WorldGlobals.h"
+
+WorldGlobals* WorldGlobals::instance()
+{
+ static WorldGlobals instance;
+ return &instance;
+}
+
+void WorldGlobals::LoadAntiDosOpcodePolicies()
+{
+ uint32 oldMSTime = getMSTime();
+
+ _antiDosOpcodePolicies = {};
+
+ QueryResult result = WorldDatabase.Query("SELECT Opcode, Policy, MaxAllowedCount FROM antidos_opcode_policies");
+ if (!result)
+ {
+ LOG_WARN("server.loading", ">> Loaded 0 AntiDos Opcode Policies. DB table `antidos_opcode_policies` is empty!");
+ LOG_INFO("server.loading", " ");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint16 opcode = fields[0].Get();
+ if (opcode >= NUM_OPCODE_HANDLERS)
+ {
+ LOG_ERROR("server.loading", "Unkown opcode {} in table `antidos_opcode_policies`, skipping.", opcode);
+ continue;
+ }
+
+ std::unique_ptr policy = std::make_unique();
+ policy->Policy = fields[1].Get();
+ policy->MaxAllowedCount = fields[2].Get();
+
+ _antiDosOpcodePolicies[opcode] = std::move(policy);
+
+ ++count;
+ } while (result->NextRow());
+
+ LOG_INFO("server.loading", ">> Loaded {} AntiDos Opcode Policies in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
+ LOG_INFO("server.loading", " ");
+}
+
+AntiDosOpcodePolicy const* WorldGlobals::GetAntiDosPolicyForOpcode(uint16 opcode)
+{
+ if (opcode >= NUM_OPCODE_HANDLERS)
+ return nullptr;
+
+ return _antiDosOpcodePolicies[opcode].get();
+}
diff --git a/src/server/game/Globals/WorldGlobals.h b/src/server/game/Globals/WorldGlobals.h
new file mode 100644
index 000000000..e8695d02b
--- /dev/null
+++ b/src/server/game/Globals/WorldGlobals.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the AzerothCore 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 Affero General Public License as published by the
+ * Free Software Foundation; either version 3 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 Affero 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 __WORLDGLOBALS_H
+#define __WORLDGLOBALS_H
+
+#include "Common.h"
+#include "Opcodes.h"
+
+struct AntiDosOpcodePolicy
+{
+ uint8 Policy;
+ uint16 MaxAllowedCount;
+};
+
+class WorldGlobals
+{
+public:
+ static WorldGlobals* instance();
+
+ void LoadAntiDosOpcodePolicies();
+ AntiDosOpcodePolicy const* GetAntiDosPolicyForOpcode(uint16 opcode);
+
+private:
+ std::array, NUM_OPCODE_HANDLERS> _antiDosOpcodePolicies;
+};
+
+#define sWorldGlobals WorldGlobals::instance()
+
+#endif
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index c54bcab8d..823d52976 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2212,15 +2212,6 @@ bool InstanceMap::AddPlayerToMap(Player* player)
m_resetAfterUnload = false;
m_unloadWhenEmpty = false;
- if (instance_data && instance_data->IsTwoFactionInstance()
- && instance_data->GetTeamIdInInstance() == TEAM_NEUTRAL)
- {
- instance_data->SetTeamIdInInstance(player->GetTeamId());
- if (Group* group = player->GetGroup())
- if (Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()))
- instance_data->SetTeamIdInInstance(leader->GetTeamId());
- }
-
// this will acquire the same mutex so it cannot be in the previous block
Map::AddPlayerToMap(player);
diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp
index 8b42389e3..9d8172a73 100644
--- a/src/server/game/Maps/MapInstanced.cpp
+++ b/src/server/game/Maps/MapInstanced.cpp
@@ -147,7 +147,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player)
map = FindInstanceMap(destInstId);
if (!map)
- map = CreateInstance(destInstId, pSave, realdiff);
+ map = CreateInstance(destInstId, pSave, realdiff, player);
else if (IsSharedDifficultyMap(mapId) && !map->HavePlayers() && map->GetDifficulty() != realdiff)
{
if (player->isBeingLoaded()) // pussywizard: crashfix (assert(passengers.empty) fail in ~transport), could be added to a transport during loading from db
@@ -160,7 +160,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player)
if (i->first == destInstId)
{
DestroyInstance(i);
- map = CreateInstance(destInstId, pSave, realdiff);
+ map = CreateInstance(destInstId, pSave, realdiff, player);
break;
}
}
@@ -170,14 +170,14 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player)
uint32 newInstanceId = sMapMgr->GenerateInstanceId();
ASSERT(!FindInstanceMap(newInstanceId)); // pussywizard: instance with new id can't exist
Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid());
- map = CreateInstance(newInstanceId, nullptr, diff);
+ map = CreateInstance(newInstanceId, nullptr, diff, player);
}
}
return map;
}
-InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty)
+InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, Player* player)
{
// load/create a map
std::lock_guard guard(Lock);
@@ -213,6 +213,16 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save,
else
map->CreateInstanceScript(false, "", 0);
+ if (map->GetInstanceScript() && map->GetInstanceScript()->IsTwoFactionInstance()
+ && map->GetInstanceScript()->GetTeamIdInInstance() == TEAM_NEUTRAL)
+ {
+ ASSERT(player); // Player should exist, as checked by in MapInstanced::CreateInstanceForPlayer
+ map->GetInstanceScript()->SetTeamIdInInstance(player->GetTeamId());
+ if (Group* group = player->GetGroup())
+ if (Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()))
+ map->GetInstanceScript()->SetTeamIdInInstance(leader->GetTeamId());
+ }
+
map->OnCreateMap();
if (!save) // this is for sure a dungeon (assert above), no need to check here
diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h
index f08c5687a..e50057c9e 100644
--- a/src/server/game/Maps/MapInstanced.h
+++ b/src/server/game/Maps/MapInstanced.h
@@ -50,7 +50,7 @@ public:
void InitVisibilityDistance() override;
private:
- InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty);
+ InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, Player* player);
BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg);
InstancedMaps m_InstancedMaps;
diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp
index 422a397df..bf3641d35 100644
--- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp
+++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp
@@ -214,18 +214,16 @@ void ScriptMgr::OnPlayerBeforeUpdate(Player* player, uint32 p_time)
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_BEFORE_UPDATE, script->OnPlayerBeforeUpdate(player, p_time));
}
+void ScriptMgr::OnPlayerAfterUpdate(Player* player, uint32 p_time)
+{
+ CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_AFTER_UPDATE, script->OnPlayerAfterUpdate(player, p_time));
+}
+
void ScriptMgr::OnPlayerUpdate(Player* player, uint32 p_time)
{
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_UPDATE, script->OnPlayerUpdate(player, p_time));
}
-void ScriptMgr::OnPlayerAfterUpdate(Player* player, uint32 diff)
-{
- ExecuteScript([&](PlayerScript* script)
- {
- script->OnPlayerAfterUpdate(player, diff);
- });
-}
void ScriptMgr::OnPlayerLogin(Player* player)
{
diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.h b/src/server/game/Scripting/ScriptDefines/PlayerScript.h
index c640e5e6e..47c266396 100644
--- a/src/server/game/Scripting/ScriptDefines/PlayerScript.h
+++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.h
@@ -45,6 +45,7 @@ enum PlayerHook
PLAYERHOOK_ON_AFTER_SPEC_SLOT_CHANGED,
PLAYERHOOK_ON_BEFORE_UPDATE,
PLAYERHOOK_ON_UPDATE,
+ PLAYERHOOK_ON_AFTER_UPDATE,
PLAYERHOOK_ON_MONEY_CHANGED,
PLAYERHOOK_ON_BEFORE_LOOT_MONEY,
PLAYERHOOK_ON_GIVE_EXP,
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index fd7c86713..dab404a86 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -49,6 +49,7 @@
#include "Vehicle.h"
#include "WardenWin.h"
#include "World.h"
+#include "WorldGlobals.h"
#include "WorldPacket.h"
#include "WorldSocket.h"
#include "WorldState.h"
@@ -343,145 +344,150 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
METRIC_DETAILED_TIMER("worldsession_update_opcode_time", METRIC_TAG("opcode", opHandle->Name));
LOG_DEBUG("network", "message id {} ({}) under READ", opcode, opHandle->Name);
- try
+ WorldSession::DosProtection::Policy const evaluationPolicy = AntiDOS.EvaluateOpcode(*packet, currentTime);
+ switch (evaluationPolicy)
{
- switch (opHandle->Status)
- {
- case STATUS_LOGGEDIN:
- if (!_player)
- {
- // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
- //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
- //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
- if (!m_playerRecentlyLogout)
- {
- requeuePackets.push_back(packet);
- deletePacket = false;
+ case WorldSession::DosProtection::Policy::Kick:
+ case WorldSession::DosProtection::Policy::Ban:
+ processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE;
+ break;
+ case WorldSession::DosProtection::Policy::BlockingThrottle:
+ requeuePackets.push_back(packet);
+ deletePacket = false;
+ processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE;
+ break;
+ default:
+ break;
+ }
- LOG_DEBUG("network", "Delaying processing of message with status STATUS_LOGGEDIN: No players in the world for account id {}", GetAccountId());
- }
- }
- else if (_player->IsInWorld())
+ if (evaluationPolicy == WorldSession::DosProtection::Policy::Process
+ || evaluationPolicy == WorldSession::DosProtection::Policy::Log)
+ {
+ try
+ {
+ switch (opHandle->Status)
{
- if (AntiDOS.EvaluateOpcode(*packet, currentTime))
+ case STATUS_LOGGEDIN:
+ if (!_player)
+ {
+ // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
+ //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
+ //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
+ if (!m_playerRecentlyLogout)
+ {
+ requeuePackets.push_back(packet);
+ deletePacket = false;
+
+ LOG_DEBUG("network", "Delaying processing of message with status STATUS_LOGGEDIN: No players in the world for account id {}", GetAccountId());
+ }
+ }
+ else if (_player->IsInWorld())
{
if (!sScriptMgr->CanPacketReceive(this, *packet))
- {
break;
- }
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
+#ifdef MOD_PLAYERBOTS
sScriptMgr->OnPacketReceived(this, *packet);
+#endif
+ }
+
+ // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
+ break;
+ case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
+ if (!_player && !m_playerRecentlyLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
+ {
+ LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
+ "the player has not logged in yet and not recently logout");
}
else
- processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
- }
-
- // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
- break;
- case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
- if (!_player && !m_playerRecentlyLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
- {
- LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
- "the player has not logged in yet and not recently logout");
- }
- else if (AntiDOS.EvaluateOpcode(*packet, currentTime))
- {
- // not expected _player or must checked in packet hanlder
- if (!sScriptMgr->CanPacketReceive(this, *packet))
- break;
-
- opHandle->Call(this, *packet);
- LogUnprocessedTail(packet);
-
- sScriptMgr->OnPacketReceived(this, *packet);
- }
- else
- processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
- break;
- case STATUS_TRANSFER:
- if (_player && !_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
- {
- if (!sScriptMgr->CanPacketReceive(this, *packet))
{
- break;
+ // not expected _player or must checked in packet hanlder
+ if (!sScriptMgr->CanPacketReceive(this, *packet))
+ break;
+
+ opHandle->Call(this, *packet);
+ LogUnprocessedTail(packet);
+#ifdef MOD_PLAYERBOTS
+ sScriptMgr->OnPacketReceived(this, *packet);
+#endif
}
-
- opHandle->Call(this, *packet);
- LogUnprocessedTail(packet);
-
- sScriptMgr->OnPacketReceived(this, *packet);
- }
- else
- processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
- break;
- case STATUS_AUTHED:
- if (m_inQueue) // prevent cheating
break;
-
- // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
- // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
- if (packet->GetOpcode() == CMSG_CHAR_ENUM)
- m_playerRecentlyLogout = false;
-
- if (AntiDOS.EvaluateOpcode(*packet, currentTime))
- {
- if (!sScriptMgr->CanPacketReceive(this, *packet))
+ case STATUS_TRANSFER:
+ if (_player && !_player->IsInWorld())
{
- break;
+ if (!sScriptMgr->CanPacketReceive(this, *packet))
+ break;
+
+ opHandle->Call(this, *packet);
+ LogUnprocessedTail(packet);
+#ifdef MOD_PLAYERBOTS
+ sScriptMgr->OnPacketReceived(this, *packet);
+#endif
}
+ break;
+ case STATUS_AUTHED:
+ if (m_inQueue) // prevent cheating
+ break;
+
+ // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
+ // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
+ if (packet->GetOpcode() == CMSG_CHAR_ENUM)
+ m_playerRecentlyLogout = false;
+
+ if (!sScriptMgr->CanPacketReceive(this, *packet))
+ break;
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
-
+#ifdef MOD_PLAYERBOTS
sScriptMgr->OnPacketReceived(this, *packet);
+#endif
+ break;
+ case STATUS_NEVER:
+ LOG_ERROR("network.opcode", "Received not allowed opcode {} from {}",
+ GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
+ break;
+ case STATUS_UNHANDLED:
+ LOG_DEBUG("network.opcode", "Received not handled opcode {} from {}",
+ GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
+ break;
}
- else
- processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
- break;
- case STATUS_NEVER:
- LOG_ERROR("network.opcode", "Received not allowed opcode {} from {}",
- GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
- break;
- case STATUS_UNHANDLED:
- LOG_DEBUG("network.opcode", "Received not handled opcode {} from {}",
- GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
- break;
}
- }
- catch (WorldPackets::InvalidHyperlinkException const& ihe)
- {
- LOG_ERROR("network", "{} sent {} with an invalid link:\n{}", GetPlayerInfo(),
- GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), ihe.GetInvalidValue());
+ catch (WorldPackets::InvalidHyperlinkException const& ihe)
+ {
+ LOG_ERROR("network", "{} sent {} with an invalid link:\n{}", GetPlayerInfo(),
+ GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), ihe.GetInvalidValue());
- if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
- {
- KickPlayer("WorldSession::Update Invalid chat link");
+ if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
+ {
+ KickPlayer("WorldSession::Update Invalid chat link");
+ }
}
- }
- catch (WorldPackets::IllegalHyperlinkException const& ihe)
- {
- LOG_ERROR("network", "{} sent {} which illegally contained a hyperlink:\n{}", GetPlayerInfo(),
- GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), ihe.GetInvalidValue());
+ catch (WorldPackets::IllegalHyperlinkException const& ihe)
+ {
+ LOG_ERROR("network", "{} sent {} which illegally contained a hyperlink:\n{}", GetPlayerInfo(),
+ GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), ihe.GetInvalidValue());
- if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
- {
- KickPlayer("WorldSession::Update Illegal chat link");
+ if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
+ {
+ KickPlayer("WorldSession::Update Illegal chat link");
+ }
}
- }
- catch (WorldPackets::PacketArrayMaxCapacityException const& pamce)
- {
- LOG_ERROR("network", "PacketArrayMaxCapacityException: {} while parsing {} from {}.",
- pamce.what(), GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
- }
- catch (ByteBufferException const&)
- {
- LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: {}) from client {}, accountid={}. Skipped packet.", packet->GetOpcode(), GetRemoteAddress(), GetAccountId());
- if (sLog->ShouldLog("network", LogLevel::LOG_LEVEL_DEBUG))
+ catch (WorldPackets::PacketArrayMaxCapacityException const& pamce)
{
- LOG_DEBUG("network", "Dumping error causing packet:");
- packet->hexlike();
+ LOG_ERROR("network", "PacketArrayMaxCapacityException: {} while parsing {} from {}.",
+ pamce.what(), GetOpcodeNameForLogging(static_cast(packet->GetOpcode())), GetPlayerInfo());
+ }
+ catch (ByteBufferException const&)
+ {
+ LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: {}) from client {}, accountid={}. Skipped packet.", packet->GetOpcode(), GetRemoteAddress(), GetAccountId());
+ if (sLog->ShouldLog("network", LogLevel::LOG_LEVEL_DEBUG))
+ {
+ LOG_DEBUG("network", "Dumping error causing packet:");
+ packet->hexlike();
+ }
}
}
@@ -1352,14 +1358,17 @@ Warden* WorldSession::GetWarden()
return &(*_warden);
}
-bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) const
+WorldSession::DosProtection::Policy WorldSession::DosProtection::EvaluateOpcode(WorldPacket const& p, time_t const time) const
{
- uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode());
+ AntiDosOpcodePolicy const* policy = sWorldGlobals->GetAntiDosPolicyForOpcode(p.GetOpcode());
+ if (!policy)
+ return WorldSession::DosProtection::Policy::Process; // Return true if there is no policy for the opcode
- // Return true if there no limit for the opcode
+ uint32 const maxPacketCounterAllowed = policy->MaxAllowedCount;
if (!maxPacketCounterAllowed)
- return true;
+ return WorldSession::DosProtection::Policy::Process; // Return true if there no limit for the opcode
+ // packetCounter is opcodes handled in the same world second, so MaxAllowedCount is per second
PacketCounter& packetCounter = _PacketThrottlingMap[p.GetOpcode()];
if (packetCounter.lastReceiveTime != time)
{
@@ -1369,298 +1378,57 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
// Check if player is flooding some packets
if (++packetCounter.amountCounter <= maxPacketCounterAllowed)
- return true;
+ return WorldSession::DosProtection::Policy::Process;
- LOG_WARN("network", "AntiDOS: Account {}, IP: {}, Ping: {}, Character: {}, flooding packet (opc: {} (0x{:X}), count: {})",
- Session->GetAccountId(), Session->GetRemoteAddress(), Session->GetLatency(), Session->GetPlayerName(),
- opcodeTable[static_cast(p.GetOpcode())]->Name, p.GetOpcode(), packetCounter.amountCounter);
-
- switch (_policy)
+ if (WorldSession::DosProtection::Policy(policy->Policy) != WorldSession::DosProtection::Policy::BlockingThrottle)
{
- case POLICY_LOG:
- return true;
- case POLICY_KICK:
- {
- LOG_INFO("network", "AntiDOS: Player {} kicked!", Session->GetPlayerName());
- Session->KickPlayer();
- return false;
- }
- case POLICY_BAN:
- {
- uint32 bm = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
- uint32 duration = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANDURATION); // in seconds
- std::string nameOrIp = "";
- switch (bm)
- {
- case 0: // Ban account
- (void)AccountMgr::GetName(Session->GetAccountId(), nameOrIp);
- sBan->BanAccount(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
- break;
- case 1: // Ban ip
- nameOrIp = Session->GetRemoteAddress();
- sBan->BanIP(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
- break;
- }
+ LOG_WARN("network", "AntiDOS: Account {}, IP: {}, Ping: {}, Character: {}, flooding packet (opc: {} (0x{:X}), count: {})",
+ Session->GetAccountId(), Session->GetRemoteAddress(), Session->GetLatency(), Session->GetPlayerName(),
+ opcodeTable[static_cast(p.GetOpcode())]->Name, p.GetOpcode(), packetCounter.amountCounter);
+ }
- LOG_INFO("network", "AntiDOS: Player automatically banned for {} seconds.", duration);
- return false;
+ switch (WorldSession::DosProtection::Policy(policy->Policy))
+ {
+ case WorldSession::DosProtection::Policy::Kick:
+ {
+ LOG_INFO("network", "AntiDOS: Player {} kicked!", Session->GetPlayerName());
+ Session->KickPlayer();
+ break;
+ }
+ case WorldSession::DosProtection::Policy::Ban:
+ {
+ uint32 bm = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
+ uint32 duration = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANDURATION); // in seconds
+ std::string nameOrIp = "";
+ switch (bm)
+ {
+ case 0: // Ban account
+ (void)AccountMgr::GetName(Session->GetAccountId(), nameOrIp);
+ sBan->BanAccount(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
+ break;
+ case 1: // Ban ip
+ nameOrIp = Session->GetRemoteAddress();
+ sBan->BanIP(nameOrIp, std::to_string(duration), "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
+ break;
}
+
+ LOG_INFO("network", "AntiDOS: Player automatically banned for {} seconds.", duration);
+ break;
+ }
+ case WorldSession::DosProtection::Policy::DropPacket:
+ {
+ LOG_INFO("network", "AntiDOS: Opcode packet {} from player {} will be dropped.", p.GetOpcode(), Session->GetPlayerName());
+ break;
+ }
default: // invalid policy
- return true;
- }
-}
-
-uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) const
-{
- uint32 maxPacketCounterAllowed;
- switch (opcode)
- {
- // CPU usage sending 2000 packets/second on a 3.70 GHz 4 cores on Win x64
- // [% CPU mysqld] [%CPU worldserver RelWithDebInfo]
- case CMSG_PLAYER_LOGIN: // 0 0.5
- case CMSG_NAME_QUERY: // 0 1
- case CMSG_PET_NAME_QUERY: // 0 1
- case CMSG_NPC_TEXT_QUERY: // 0 1
- case CMSG_ATTACKSTOP: // 0 1
- case CMSG_QUERY_QUESTS_COMPLETED: // 0 1
- case CMSG_QUERY_TIME: // 0 1
- case CMSG_CORPSE_MAP_POSITION_QUERY: // 0 1
- case CMSG_MOVE_TIME_SKIPPED: // 0 1
- case MSG_QUERY_NEXT_MAIL_TIME: // 0 1
- case CMSG_SET_SHEATHED: // 0 1
- case MSG_RAID_TARGET_UPDATE: // 0 1
- case CMSG_PLAYER_LOGOUT: // 0 1
- case CMSG_LOGOUT_REQUEST: // 0 1
- case CMSG_PET_RENAME: // 0 1
- case CMSG_QUESTGIVER_CANCEL: // 0 1
- case CMSG_QUESTGIVER_REQUEST_REWARD: // 0 1
- case CMSG_COMPLETE_CINEMATIC: // 0 1
- case CMSG_BANKER_ACTIVATE: // 0 1
- case CMSG_BUY_BANK_SLOT: // 0 1
- case CMSG_OPT_OUT_OF_LOOT: // 0 1
- case CMSG_DUEL_ACCEPTED: // 0 1
- case CMSG_DUEL_CANCELLED: // 0 1
- case CMSG_CALENDAR_COMPLAIN: // 0 1
- case CMSG_QUEST_QUERY: // 0 1.5
- case CMSG_ITEM_QUERY_SINGLE: // 0 1.5
- case CMSG_ITEM_NAME_QUERY: // 0 1.5
- case CMSG_GAMEOBJECT_QUERY: // 0 1.5
- case CMSG_CREATURE_QUERY: // 0 1.5
- case CMSG_QUESTGIVER_STATUS_QUERY: // 0 1.5
- case CMSG_GUILD_QUERY: // 0 1.5
- case CMSG_ARENA_TEAM_QUERY: // 0 1.5
- case CMSG_TAXINODE_STATUS_QUERY: // 0 1.5
- case CMSG_TAXIQUERYAVAILABLENODES: // 0 1.5
- case CMSG_QUESTGIVER_QUERY_QUEST: // 0 1.5
- case CMSG_PAGE_TEXT_QUERY: // 0 1.5
- case MSG_QUERY_GUILD_BANK_TEXT: // 0 1.5
- case MSG_CORPSE_QUERY: // 0 1.5
- case MSG_MOVE_SET_FACING: // 0 1.5
- case CMSG_REQUEST_PARTY_MEMBER_STATS: // 0 1.5
- case CMSG_QUESTGIVER_COMPLETE_QUEST: // 0 1.5
- case CMSG_SET_ACTION_BUTTON: // 0 1.5
- case CMSG_RESET_INSTANCES: // 0 1.5
- case CMSG_HEARTH_AND_RESURRECT: // 0 1.5
- case CMSG_TOGGLE_PVP: // 0 1.5
- case CMSG_PET_ABANDON: // 0 1.5
- case CMSG_ACTIVATETAXIEXPRESS: // 0 1.5
- case CMSG_ACTIVATETAXI: // 0 1.5
- case CMSG_SELF_RES: // 0 1.5
- case CMSG_UNLEARN_SKILL: // 0 1.5
- case CMSG_EQUIPMENT_SET_SAVE: // 0 1.5
- case CMSG_DELETEEQUIPMENT_SET: // 0 1.5
- case CMSG_DISMISS_CRITTER: // 0 1.5
- case CMSG_REPOP_REQUEST: // 0 1.5
- case CMSG_GROUP_INVITE: // 0 1.5
- case CMSG_GROUP_DECLINE: // 0 1.5
- case CMSG_GROUP_ACCEPT: // 0 1.5
- case CMSG_GROUP_UNINVITE_GUID: // 0 1.5
- case CMSG_GROUP_UNINVITE: // 0 1.5
- case CMSG_GROUP_DISBAND: // 0 1.5
- case CMSG_BATTLEMASTER_JOIN_ARENA: // 0 1.5
- case CMSG_LEAVE_BATTLEFIELD: // 0 1.5
- case MSG_GUILD_BANK_LOG_QUERY: // 0 2
- case CMSG_LOGOUT_CANCEL: // 0 2
- case CMSG_REALM_SPLIT: // 0 2
- case CMSG_ALTER_APPEARANCE: // 0 2
- case CMSG_QUEST_CONFIRM_ACCEPT: // 0 2
- case MSG_GUILD_EVENT_LOG_QUERY: // 0 2.5
- case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: // 0 2.5
- case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: // 0 2.5
- case CMSG_BEGIN_TRADE: // 0 2.5
- case CMSG_INITIATE_TRADE: // 0 3
- case CMSG_MESSAGECHAT: // 0 3.5
- case CMSG_INSPECT: // 0 3.5
- case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled
- case CMSG_STANDSTATECHANGE: // not profiled
- case MSG_RANDOM_ROLL: // not profiled
- case CMSG_TIME_SYNC_RESP: // not profiled
- case CMSG_TRAINER_BUY_SPELL: // not profiled
- case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: // not profiled
- case CMSG_FORCE_TURN_RATE_CHANGE_ACK: // not profiled
- case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: // not profiled
- {
- // "0" is a magic number meaning there's no limit for the opcode.
- // All the opcodes above must cause little CPU usage and no sync/async database queries at all
- maxPacketCounterAllowed = 0;
- break;
- }
-
- case CMSG_QUESTGIVER_ACCEPT_QUEST: // 0 4
- case CMSG_QUESTLOG_REMOVE_QUEST: // 0 4
- case CMSG_QUESTGIVER_CHOOSE_REWARD: // 0 4
- case CMSG_CONTACT_LIST: // 0 5
- case CMSG_LEARN_PREVIEW_TALENTS: // 0 6
- case CMSG_AUTOBANK_ITEM: // 0 6
- case CMSG_AUTOSTORE_BANK_ITEM: // 0 6
- case CMSG_WHO: // 0 7
- case CMSG_PLAYER_VEHICLE_ENTER: // 0 8
- case CMSG_LEARN_PREVIEW_TALENTS_PET: // not profiled
- case MSG_MOVE_HEARTBEAT:
- {
- maxPacketCounterAllowed = 200;
- break;
- }
-
- case CMSG_GUILD_SET_PUBLIC_NOTE: // 1 2 1 async db query
- case CMSG_GUILD_SET_OFFICER_NOTE: // 1 2 1 async db query
- case CMSG_SET_CONTACT_NOTES: // 1 2.5 1 async db query
- case CMSG_CALENDAR_GET_CALENDAR: // 0 1.5 medium upload bandwidth usage
- case CMSG_GUILD_BANK_QUERY_TAB: // 0 3.5 medium upload bandwidth usage
- case CMSG_QUERY_INSPECT_ACHIEVEMENTS: // 0 13 high upload bandwidth usage
- case CMSG_GAMEOBJ_REPORT_USE: // not profiled
- case CMSG_GAMEOBJ_USE: // not profiled
- case MSG_PETITION_DECLINE: // not profiled
- {
- maxPacketCounterAllowed = 50;
- break;
- }
-
- case CMSG_QUEST_POI_QUERY: // 0 25 very high upload bandwidth usage
- {
- maxPacketCounterAllowed = MAX_QUEST_LOG_SIZE;
- break;
- }
-
- case CMSG_GM_REPORT_LAG: // 1 3 1 async db query
- case CMSG_SPELLCLICK: // not profiled
- case CMSG_REMOVE_GLYPH: // not profiled
- case CMSG_DISMISS_CONTROLLED_VEHICLE: // not profiled
- {
- maxPacketCounterAllowed = 20;
- break;
- }
-
- case CMSG_PETITION_SIGN: // 9 4 2 sync 1 async db queries
- case CMSG_TURN_IN_PETITION: // 8 5.5 2 sync db query
- case CMSG_GROUP_CHANGE_SUB_GROUP: // 6 5 1 sync 1 async db queries
- case CMSG_PETITION_QUERY: // 4 3.5 1 sync db query
- case CMSG_CHAR_RACE_CHANGE: // 5 4 1 sync db query
- case CMSG_CHAR_CUSTOMIZE: // 5 5 1 sync db query
- case CMSG_CHAR_FACTION_CHANGE: // 5 5 1 sync db query
- case CMSG_CHAR_DELETE: // 4 4 1 sync db query
- case CMSG_DEL_FRIEND: // 7 5 1 async db query
- case CMSG_ADD_FRIEND: // 6 4 1 async db query
- case CMSG_CHAR_RENAME: // 5 3 1 async db query
- case CMSG_GMSURVEY_SUBMIT: // 2 3 1 async db query
- case CMSG_BUG: // 1 1 1 async db query
- case CMSG_GROUP_SET_LEADER: // 1 2 1 async db query
- case CMSG_GROUP_RAID_CONVERT: // 1 5 1 async db query
- case CMSG_GROUP_ASSISTANT_LEADER: // 1 2 1 async db query
- case CMSG_PETITION_BUY: // not profiled 1 sync 1 async db queries
- case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: // not profiled
- case CMSG_REQUEST_VEHICLE_PREV_SEAT: // not profiled
- case CMSG_REQUEST_VEHICLE_NEXT_SEAT: // not profiled
- case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: // not profiled
- case CMSG_REQUEST_VEHICLE_EXIT: // not profiled
- case CMSG_CONTROLLER_EJECT_PASSENGER: // not profiled
- case CMSG_ITEM_REFUND: // not profiled
- case CMSG_SOCKET_GEMS: // not profiled
- case CMSG_WRAP_ITEM: // not profiled
- case CMSG_REPORT_PVP_AFK: // not profiled
- case CMSG_AUCTION_LIST_ITEMS: // not profiled
- case CMSG_AUCTION_LIST_BIDDER_ITEMS: // not profiled
- case CMSG_AUCTION_LIST_OWNER_ITEMS: // not profiled
- {
- maxPacketCounterAllowed = 10;
- break;
- }
-
- case CMSG_CHAR_CREATE: // 7 5 3 async db queries
- case CMSG_CHAR_ENUM: // 22 3 2 async db queries
- case CMSG_GMTICKET_CREATE: // 1 25 1 async db query
- case CMSG_GMTICKET_UPDATETEXT: // 0 15 1 async db query
- case CMSG_GMTICKET_DELETETICKET: // 1 25 1 async db query
- case CMSG_GMRESPONSE_RESOLVE: // 1 25 1 async db query
- case CMSG_CALENDAR_ADD_EVENT: // 21 10 2 async db query
- case CMSG_CALENDAR_UPDATE_EVENT: // not profiled
- case CMSG_CALENDAR_REMOVE_EVENT: // not profiled
- case CMSG_CALENDAR_COPY_EVENT: // not profiled
- case CMSG_CALENDAR_EVENT_INVITE: // not profiled
- case CMSG_CALENDAR_EVENT_SIGNUP: // not profiled
- case CMSG_CALENDAR_EVENT_RSVP: // not profiled
- case CMSG_CALENDAR_EVENT_REMOVE_INVITE: // not profiled
- case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: // not profiled
- case CMSG_ARENA_TEAM_INVITE: // not profiled
- case CMSG_ARENA_TEAM_ACCEPT: // not profiled
- case CMSG_ARENA_TEAM_DECLINE: // not profiled
- case CMSG_ARENA_TEAM_LEAVE: // not profiled
- case CMSG_ARENA_TEAM_DISBAND: // not profiled
- case CMSG_ARENA_TEAM_REMOVE: // not profiled
- case CMSG_ARENA_TEAM_LEADER: // not profiled
- case CMSG_LOOT_METHOD: // not profiled
- case CMSG_GUILD_INVITE: // not profiled
- case CMSG_GUILD_ACCEPT: // not profiled
- case CMSG_GUILD_DECLINE: // not profiled
- case CMSG_GUILD_LEAVE: // not profiled
- case CMSG_GUILD_DISBAND: // not profiled
- case CMSG_GUILD_LEADER: // not profiled
- case CMSG_GUILD_MOTD: // not profiled
- case CMSG_GUILD_RANK: // not profiled
- case CMSG_GUILD_ADD_RANK: // not profiled
- case CMSG_GUILD_DEL_RANK: // not profiled
- case CMSG_GUILD_INFO_TEXT: // not profiled
- case CMSG_GUILD_BANK_DEPOSIT_MONEY: // not profiled
- case CMSG_GUILD_BANK_WITHDRAW_MONEY: // not profiled
- case CMSG_GUILD_BANK_BUY_TAB: // not profiled
- case CMSG_GUILD_BANK_UPDATE_TAB: // not profiled
- case CMSG_SET_GUILD_BANK_TEXT: // not profiled
- case MSG_SAVE_GUILD_EMBLEM: // not profiled
- case MSG_PETITION_RENAME: // not profiled
- case MSG_TALENT_WIPE_CONFIRM: // not profiled
- case MSG_SET_DUNGEON_DIFFICULTY: // not profiled
- case MSG_SET_RAID_DIFFICULTY: // not profiled
- case MSG_PARTY_ASSIGNMENT: // not profiled
- case MSG_RAID_READY_CHECK: // not profiled
- {
- maxPacketCounterAllowed = 3;
- break;
- }
-
- case CMSG_ITEM_REFUND_INFO: // not profiled
- {
- maxPacketCounterAllowed = PLAYER_SLOTS_COUNT;
- break;
- }
-
- default:
- {
- maxPacketCounterAllowed = 100;
- break;
- }
+ break;
}
- return maxPacketCounterAllowed;
+ return WorldSession::DosProtection::Policy(policy->Policy);
}
WorldSession::DosProtection::DosProtection(WorldSession* s) :
- Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) { }
+ Session(s) { }
void WorldSession::ResetTimeSync()
{
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index e2b73bef7..0816b734e 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -341,7 +341,7 @@ protected:
struct PacketCounter
{
time_t lastReceiveTime;
- uint32 amountCounter;
+ uint16 amountCounter;
};
/// Player session in the World
@@ -1134,22 +1134,21 @@ protected:
{
friend class World;
public:
- DosProtection(WorldSession* s);
- bool EvaluateOpcode(WorldPacket& p, time_t time) const;
- protected:
- enum Policy
+ enum class Policy
{
- POLICY_LOG,
- POLICY_KICK,
- POLICY_BAN
+ Process,
+ Kick,
+ Ban,
+ Log,
+ BlockingThrottle,
+ DropPacket
};
- uint32 GetMaxPacketCounterAllowed(uint16 opcode) const;
-
+ DosProtection(WorldSession* s);
+ Policy EvaluateOpcode(WorldPacket const& p, time_t const time) const;
+ protected:
WorldSession* Session;
-
private:
- Policy _policy;
typedef std::unordered_map PacketThrottlingMap;
// mark this member as "mutable" so it can be modified even in const functions
mutable PacketThrottlingMap _PacketThrottlingMap;
diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp
index dc2ecf080..35092327e 100644
--- a/src/server/game/Spells/SpellInfoCorrections.cpp
+++ b/src/server/game/Spells/SpellInfoCorrections.cpp
@@ -4884,6 +4884,13 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_1].RealPointsPerLevel = 0.25;
});
+ // Smash
+ // Dark Smash
+ ApplySpellFix({ 42669, 59706, 42723, 59709 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->AttributesEx2 &= ~SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
+ });
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h
index f8359ce7a..40cc8a7c5 100644
--- a/src/server/game/World/IWorld.h
+++ b/src/server/game/World/IWorld.h
@@ -367,7 +367,6 @@ enum WorldIntConfigs
CONFIG_WINTERGRASP_BATTLETIME,
CONFIG_WINTERGRASP_NOBATTLETIME,
CONFIG_WINTERGRASP_RESTART_AFTER_CRASH,
- CONFIG_PACKET_SPOOF_POLICY,
CONFIG_PACKET_SPOOF_BANMODE,
CONFIG_PACKET_SPOOF_BANDURATION,
CONFIG_WARDEN_CLIENT_RESPONSE_DELAY,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index b25d733b5..62482da15 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -91,6 +91,7 @@
#include "WaypointMovementGenerator.h"
#include "WeatherMgr.h"
#include "WhoListCacheMgr.h"
+#include "WorldGlobals.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "WorldSessionMgr.h"
@@ -1197,7 +1198,6 @@ void World::LoadConfigSettings(bool reload)
_bool_configs[CONFIG_SET_ALL_CREATURES_WITH_WAYPOINT_MOVEMENT_ACTIVE] = sConfigMgr->GetOption("SetAllCreaturesWithWaypointMovementActive", false);
// packet spoof punishment
- _int_configs[CONFIG_PACKET_SPOOF_POLICY] = sConfigMgr->GetOption("PacketSpoof.Policy", (uint32)WorldSession::DosProtection::POLICY_KICK);
_int_configs[CONFIG_PACKET_SPOOF_BANMODE] = sConfigMgr->GetOption("PacketSpoof.BanMode", (uint32)0);
if (_int_configs[CONFIG_PACKET_SPOOF_BANMODE] > 1)
_int_configs[CONFIG_PACKET_SPOOF_BANMODE] = (uint32)0;
@@ -1953,6 +1953,9 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Load Channels...");
ChannelMgr::LoadChannels();
+ LOG_INFO("server.loading", "Loading AntiDos opcode policies");
+ sWorldGlobals->LoadAntiDosOpcodePolicies();
+
sScriptMgr->OnBeforeWorldInitialized();
if (sWorld->getBoolConfig(CONFIG_PRELOAD_ALL_NON_INSTANCED_MAP_GRIDS))
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 62bfe7712..45434d502 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -47,6 +47,7 @@ EndScriptData */
#include "Tokenize.h"
#include "WardenCheckMgr.h"
#include "WaypointMgr.h"
+#include "WorldGlobals.h"
using namespace Acore::ChatCommands;
@@ -73,6 +74,7 @@ public:
};
static ChatCommandTable reloadCommandTable =
{
+ { "antidos_opcode_policies", HandleReloadAntiDosOpcodePoliciesCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "auctions", HandleReloadAuctionsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "dungeon_access_template", HandleReloadDungeonAccessCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "dungeon_access_requirements", HandleReloadDungeonAccessCommand, SEC_ADMINISTRATOR, Console::Yes },
@@ -1199,6 +1201,14 @@ public:
return true;
}
+ static bool HandleReloadAntiDosOpcodePoliciesCommand(ChatHandler* handler)
+ {
+ LOG_INFO("server.loading", "Reloading AntiDos opcode policies...");
+ sWorldGlobals->LoadAntiDosOpcodePolicies();
+ handler->SendGlobalGMSysMessage("AntiDos opcode policies reloaded.");
+ return true;
+ }
+
static bool HandleReloadAuctionsCommand(ChatHandler* handler)
{
///- Reload dynamic data tables from the database
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
index a47d16bda..75de3d41c 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
@@ -377,6 +377,35 @@ class spell_eredar_twins_blaze : public SpellScript
}
};
+class spell_eredar_twins_handle_touch_periodic : public AuraScript
+{
+ PrepareAuraScript(spell_eredar_twins_handle_touch_periodic);
+
+public:
+ spell_eredar_twins_handle_touch_periodic(uint32 touchSpell, uint8 effIndex, uint8 aura) : AuraScript(), _touchSpell(touchSpell), _effectIndex(effIndex), _aura(aura) {}
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ _touchSpell });
+ }
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* owner = GetOwner()->ToUnit())
+ owner->CastSpell(owner, _touchSpell, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_eredar_twins_handle_touch_periodic::OnPeriodic, _effectIndex, _aura);
+ }
+
+private:
+ uint32 _touchSpell;
+ uint8 _effectIndex;
+ uint8 _aura;
+};
+
class at_sunwell_eredar_twins : public OnlyOnceAreaTriggerScript
{
public:
@@ -404,5 +433,8 @@ void AddSC_boss_eredar_twins()
RegisterSpellScriptWithArgs(spell_eredar_twins_apply_touch, "spell_eredar_twins_apply_flame_touched", SPELL_FLAME_TOUCHED);
RegisterSpellScript(spell_eredar_twins_handle_touch);
RegisterSpellScript(spell_eredar_twins_blaze);
+ RegisterSpellScriptWithArgs(spell_eredar_twins_handle_touch_periodic, "spell_eredar_twins_handle_dark_touched_periodic", SPELL_DARK_TOUCHED, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
+ RegisterSpellScriptWithArgs(spell_eredar_twins_handle_touch_periodic, "spell_eredar_twins_handle_flame_touched_periodic", SPELL_FLAME_TOUCHED, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ RegisterSpellScriptWithArgs(spell_eredar_twins_handle_touch_periodic, "spell_eredar_twins_handle_flame_touched_flame_sear", SPELL_FLAME_TOUCHED, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
new at_sunwell_eredar_twins();
}
diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
index 7e1f7465c..aaaaf409c 100644
--- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
@@ -710,7 +710,6 @@ private:
enum AmanishiScout
{
NPC_WORLD_TRIGGER = 22515,
- POINT_DRUM = 0,
SAY_AGGRO = 0,
SPELL_ALERT_DRUMS = 42177,
SPELL_MULTI_SHOT = 43205,
@@ -737,6 +736,8 @@ struct npc_amanishi_scout : public ScriptedAI
{
scheduler.CancelAll();
me->SetCombatMovement(false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ _drumGUID.Clear();
}
void JustEngagedWith(Unit* /*who*/) override
@@ -748,30 +749,38 @@ struct npc_amanishi_scout : public ScriptedAI
GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 50.0f);
triggers.remove_if([](Creature* trigger) {return !IsDrum(trigger);});
triggers.sort(Acore::ObjectDistanceOrderPred(me));
- if (!triggers.empty())
- {
- me->ClearTarget();
- Creature* closestDrum = triggers.front();
- me->GetMotionMaster()->MovePoint(POINT_DRUM, closestDrum->GetPositionX(), closestDrum->GetPositionY(), closestDrum->GetPositionZ());
- }
- else
+ if (triggers.empty())
ScheduleCombat();
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == POINT_DRUM)
+ Creature* closestDrum = triggers.front();
+ me->GetMotionMaster()->MoveFollow(closestDrum, 0.0f, 0.0f);
+ _drumGUID = closestDrum->GetGUID();
+ me->ClearTarget();
+ me->SetReactState(REACT_PASSIVE);
+ scheduler.Schedule(1s, [this](TaskContext context)
{
- DoCastSelf(SPELL_ALERT_DRUMS);
- scheduler.Schedule(5s, [this](TaskContext /*context*/)
- {
- ScheduleCombat();
- });
- }
+ if (_drumGUID)
+ if (Creature* drum = ObjectAccessor::GetCreature(*me, _drumGUID))
+ {
+ if (me->IsWithinRange(drum, INTERACTION_DISTANCE))
+ {
+ me->SetFacingToObject(drum);
+ DoCastSelf(SPELL_ALERT_DRUMS);
+ scheduler.Schedule(5s, [this](TaskContext /*context*/)
+ {
+ ScheduleCombat();
+ });
+ return;
+ }
+ context.Repeat(1s);
+ return;
+ }
+ ScheduleCombat();
+ });
}
void ScheduleCombat()
{
+ me->SetReactState(REACT_AGGRESSIVE);
me->SetCombatMovement(true);
if (Unit* victim = me->GetVictim())
me->GetMotionMaster()->MoveChase(victim);
@@ -790,11 +799,13 @@ struct npc_amanishi_scout : public ScriptedAI
{
scheduler.Update(diff);
- if (!UpdateVictim())
+ if (!me->IsCombatMovementAllowed() || !UpdateVictim())
return;
DoMeleeAttackIfReady();
}
+private:
+ ObjectGuid _drumGUID;
};
enum SpellAlertDrums
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
index c39c3a5e6..812e2f3e5 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
@@ -46,7 +46,6 @@ public:
}
uint32 m_auiEncounter[MAX_ENCOUNTER];
- TeamId teamIdInInstance;
std::string str_data;
ObjectGuid NPC_BronjahmGUID;
ObjectGuid NPC_DevourerGUID;
@@ -59,7 +58,6 @@ public:
void Initialize() override
{
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
- teamIdInInstance = TEAM_NEUTRAL;
}
bool IsEncounterInProgress() const override
@@ -72,21 +70,7 @@ public:
void OnPlayerEnter(Player* player) override
{
- if (teamIdInInstance == TEAM_NEUTRAL)
- {
- if (Group* group = player->GetGroup())
- {
- if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
- teamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
- else
- teamIdInInstance = player->GetTeamId();
- }
- else
- teamIdInInstance = player->GetTeamId();
- }
-
- if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
- player->SetFaction((teamIdInInstance == TEAM_HORDE) ? 1610 : 1);
+ InstanceScript::OnPlayerEnter(player);
// this will happen only after crash and loading the instance from db
if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && (!NPC_LeaderSecondGUID || !instance->GetCreature(NPC_LeaderSecondGUID)))
@@ -98,24 +82,6 @@ public:
void OnCreatureCreate(Creature* creature) override
{
- if (teamIdInInstance == TEAM_NEUTRAL)
- {
- Map::PlayerList const& players = instance->GetPlayers();
- if (!players.IsEmpty())
- if (Player* player = players.begin()->GetSource())
- {
- if (Group* group = player->GetGroup())
- {
- if (Player* gLeader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()))
- teamIdInInstance = Player::TeamIdForRace(gLeader->getRace());
- else
- teamIdInInstance = player->GetTeamId();
- }
- else
- teamIdInInstance = player->GetTeamId();
- }
- }
-
switch (creature->GetEntry())
{
case NPC_BRONJAHM:
@@ -125,7 +91,7 @@ public:
NPC_DevourerGUID = creature->GetGUID();
break;
case NPC_SYLVANAS_PART1:
- if (teamIdInInstance == TEAM_ALLIANCE)
+ if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART1);
NPC_LeaderFirstGUID = creature->GetGUID();
@@ -133,12 +99,12 @@ public:
creature->SetVisible(false);
break;
case NPC_SYLVANAS_PART2:
- if (teamIdInInstance == TEAM_ALLIANCE)
+ if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_JAINA_PART2);
NPC_LeaderSecondGUID = creature->GetGUID();
break;
case NPC_LORALEN:
- if (teamIdInInstance == TEAM_ALLIANCE)
+ if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_ELANDRA);
if (!NPC_GuardFirstGUID)
{
@@ -148,7 +114,7 @@ public:
}
break;
case NPC_KALIRA:
- if (teamIdInInstance == TEAM_ALLIANCE)
+ if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_KORELN);
if (!NPC_GuardSecondGUID)
{
@@ -170,9 +136,12 @@ public:
leader->GetMotionMaster()->MovePoint(1, boss->GetPositionX() + 10.0f * cos(angle), boss->GetPositionY() + 10.0f * std::sin(angle), boss->GetPositionZ());
}
- for (int8 i = 0; outroPositions[i].entry[teamIdInInstance] != 0; ++i)
- if (Creature* summon = instance->SummonCreature(outroPositions[i].entry[teamIdInInstance], outroPositions[i].startPosition))
- summon->GetMotionMaster()->MovePath(outroPositions[i].pathId, false);
+ if (GetTeamIdInInstance() < TEAM_NEUTRAL) // Shouldn't happen, but just in case.
+ {
+ for (int8 i = 0; outroPositions[i].entry[GetTeamIdInInstance()] != 0; ++i)
+ if (Creature* summon = instance->SummonCreature(outroPositions[i].entry[GetTeamIdInInstance()], outroPositions[i].startPosition))
+ summon->GetMotionMaster()->MovePath(outroPositions[i].pathId, false);
+ }
}
void SetData(uint32 type, uint32 data) override
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 637b355ab..ba7a82768 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -887,8 +887,11 @@ class spell_hun_misdirection : public AuraScript
GetTarget()->ResetRedirectThreat();
}
- bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ bool CheckProc(ProcEventInfo& eventInfo)
{
+ // Do not trigger from Mend Pet
+ if (eventInfo.GetProcSpell() && (eventInfo.GetProcSpell()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000))
+ return false;
return GetTarget()->GetRedirectThreatTarget();
}