aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--sql/updates/world/2014_09_08_01_world_freeze_cmd.sql17
-rw-r--r--sql/updates/world/2014_09_09_00_world_sai.sql162
-rw-r--r--sql/updates/world/2014_09_09_01_world_sai.sql8
-rw-r--r--sql/updates/world/2014_09_09_03_world_misc.sql14
-rw-r--r--src/server/authserver/Main.cpp3
-rw-r--r--src/server/authserver/Server/AuthSession.cpp121
-rw-r--r--src/server/authserver/Server/AuthSession.h14
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp3
-rw-r--r--src/server/game/Entities/Creature/Creature.h35
-rw-r--r--src/server/game/Miscellaneous/Language.h4
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSocket.cpp122
-rw-r--r--src/server/game/Server/WorldSocket.h67
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp115
-rw-r--r--src/server/game/Server/WorldSocketMgr.h66
-rw-r--r--src/server/game/World/World.cpp1
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp150
-rw-r--r--src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp38
-rw-r--r--src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp15
-rw-r--r--src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h4
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp8
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp182
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp74
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp2
-rw-r--r--src/server/shared/Networking/AsyncAcceptor.h52
-rw-r--r--src/server/shared/Networking/MessageBuffer.h67
-rw-r--r--src/server/shared/Networking/NetworkThread.h166
-rw-r--r--src/server/shared/Networking/Socket.h255
-rw-r--r--src/server/shared/Networking/SocketMgr.h111
-rw-r--r--src/server/worldserver/Main.cpp18
-rw-r--r--src/server/worldserver/worldserver.conf.dist8
33 files changed, 1315 insertions, 592 deletions
diff --git a/.travis.yml b/.travis.yml
index f6e085b58be..e8ff00f425f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ install:
- mysql -uroot -e 'create database test_mysql;'
- mkdir bin
- cd bin
- - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=1 -DUSE_COREPCH=0 -DUSE_SCRIPTPCH=0 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release
+ - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release
script:
- cd ..
diff --git a/sql/updates/world/2014_09_08_01_world_freeze_cmd.sql b/sql/updates/world/2014_09_08_01_world_freeze_cmd.sql
new file mode 100644
index 00000000000..e2c7d53336b
--- /dev/null
+++ b/sql/updates/world/2014_09_08_01_world_freeze_cmd.sql
@@ -0,0 +1,17 @@
+-- GM Freeze Spell Script
+DELETE FROM `spell_script_names` WHERE `spell_id`=9454;
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (9454, 'spell_gen_gm_freeze');
+
+-- Update Command Help
+UPDATE `command` SET `help`='Syntax: .freeze [#player] [#duration]
+Freezes #player for #duration (seconds)
+Freezes the selected player if no arguments are given.
+Default duration: GM.FreezeAuraDuration (worldserver.conf)' WHERE `name`='freeze';
+
+-- Add new string to show the duration on the freeze upon using .listfreeze
+DELETE FROM `trinity_string` WHERE `entry`=5019;
+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
+(5019, '| %s - Status: %d seconds left');
+
+-- Update old string to show if the duration is permanent
+UPDATE `trinity_string` SET `content_default`='| %s - Status: Permanently frozen' WHERE `entry`=5006;
diff --git a/sql/updates/world/2014_09_09_00_world_sai.sql b/sql/updates/world/2014_09_09_00_world_sai.sql
new file mode 100644
index 00000000000..4037b19df09
--- /dev/null
+++ b/sql/updates/world/2014_09_09_00_world_sai.sql
@@ -0,0 +1,162 @@
+SET @CGUID := 29979;
+
+DELETE FROM `creature_text` WHERE `entry` IN(26097,25380,25602,25834,25849,25983,25380,25401);
+DELETE FROM `creature_text` WHERE `entry` =23837 AND `groupid`=1;
+
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(26097, 0, 0, 'Thank you for saving us. We accidentally uncovered the pieces of Gearmaster Mechazod and reassembled him.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25205),
+(26097, 1, 0, 'In return, he ''de-cursed'' us, saying that we were being ''fixed'' by returning us to the state of being mechanical constructs.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25207),
+(26097, 2, 0, 'He claims that all creations of the Titans fall prey to what he calls, ''The Curse of Flesh''. He says that the original gnomes were once mechagnomes.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25208),
+(26097, 3, 0, 'He''s quite insane! Someone must put a stop to his madness before it''s too late for everyone!', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25209),
+(25602, 0, 0, 'Now, $n, let us release their souls and hear what they have to say.', 12, 0, 100, 1, 0, 0, 'Greatmother Taiga',25204),
+(25602, 1, 0, 'This is dire news indeed!', 12, 0, 100, 1, 0, 0, 'Greatmother Taiga',25211),
+(25380, 0, 0, 'And remember, $n, the bloodspore powder can be used to weaken all magnataur in Gammoth.', 15, 0, 100, 0, 0, 0, 'Primal Mighthorn',24994),
+(25834, 0, 0, 'You were looking for me, child? Why do you come to kill me, $n? I only wish to help.', 12, 0, 100, 6, 0, 0, 'Gearmaster Mechazod',25024),
+(25834, 1, 0, 'Now that I have been reassembled, we can return to a time of perfection... the time of the Titans!', 12, 0, 100, 1, 0, 0, 'Gearmaster Mechazod',25025),
+(25834, 2, 0, 'But, I can see it in your eyes, hear it in your pulse rate. You would destroy me despite my offer of immortality!', 12, 0, 100, 25, 0, 0, 'Gearmaster Mechazod',25026),
+(25834, 3, 0, 'Very well. It saddens me that it has come to this. I look upon all of you as if you were my children. I will slay you if I must!', 12, 0, 100, 25, 0, 0, 'Gearmaster Mechazod',25027),
+(23837, 1, 0, 'There is a noise from behind you!', 41, 0, 100, 0, 0, 0, 'ELM General Purpose Bunny',25215),
+(25849, 0, 0, 'It''s really going to work this time... right?', 12, 0, 100, 6, 0, 0, 'Fezzix Geartwist',25143),
+(25849, 1, 0, 'It works, Dorain! Look! It actually works...', 12, 0, 100, 4, 0, 0, 'Fezzix Geartwist',25148),
+(25849, 2, 0, 'Here I goooooooooo!', 12, 0, 100, 0, 0, 0, 'Fezzix Geartwist',25150),
+(25849, 3, 0, 'OUCH!', 12, 0, 100, 0, 0, 0, 'Fezzix Geartwist',25151),
+(25849, 4, 0, 'I give up! So much for goblin ingenuity!', 12, 0, 100, 5, 0, 0, 'Fezzix Geartwist',25152),
+(25983, 0, 0, 'Fezzix, I think we''ve solved your little engine problem.', 12, 0, 100, 1, 0, 0, 'Dorain Frosthoof',25132),
+(25401, 0, 0, '%s armed.', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24590),
+(25401, 1, 0, 'Detonation in 5...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24591),
+(25401, 2, 0, '4...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24592),
+(25401, 3, 0, '3...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24593),
+(25401, 4, 0, '2...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24594),
+(25401, 5, 0, '1...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24595);
+
+UPDATE `creature_template` SET `unit_flags`=33024 WHERE `entry`=25834;
+UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(26097,35426,25602,25983,25849,25834,25380,25401);
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN(26097,35426,25602,25983,25849,25834,25380,25401) AND `source_type`=0;
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN(2560200,2598300,2584900,2584901,2583400,2540100) AND `source_type`=9;
+
+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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(25401, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - On Just Summoned - Store Targetlist'),
+(25401, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2540100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - On Just Summoned - Run Script'),
+(25401, 0, 2, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45506, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (SW) '),
+(25401, 0, 3, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45508, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (SE)'),
+(25401, 0, 4, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45510, 2, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (NW)'),
+(25401, 0, 5, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45512, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (NE)'),
+(25834, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Just Summoned - Store Targetlist'),
+(25834, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2583400, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Just Summoned - Run Script'),
+(25834, 0, 2, 0, 7, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Evade Despawn'),
+(25380, 0, 0, 0, 19, 0, 100, 0, 11721, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Primal Mighthorn - On Quest Accept (Gammothra the Tormentor) - Say Line 1'),
+(26097, 0, 0, 0, 1, 0, 100, 1, 1000, 1000, 0, 0, 11, 35426, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Gnome Ghost - OOC (No Repeat) - Cast Arcane Explosion Visual'),
+(26097, 0, 1, 0, 54, 0, 100, 0, 0, 0, 0, 0, 11, 32423, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Gnome Ghost - On Just Summoned - Cast Blue Radiation'),
+(25602, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Reset Set Phase 1'),
+(25602, 0, 1, 2, 20, 1, 100, 0, 11899, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Quest Reward (Souls of the Decursed) - Say Line 1 (Phase 1)'),
+(25602, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2560200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Quest Reward (Souls of the Decursed) - Run Script (Phase 1)'),
+(25983, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - On Reset Set Phase 1'),
+(25983, 0, 1, 2, 20, 1, 100, 0, 11893, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - - On Quest Reward (The Power of the Elements) - Say Line 1'),
+(25983, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2598300, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - - On Quest Reward (The Power of the Elements) - Run Script'),
+(25849, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - On Reset Set Phase 1'),
+(25849, 0, 1, 2, 20, 1, 100, 0, 11894, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Quest Reward (Patching Up) - Say Line 1'),
+(25849, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2584900, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Quest Reward (Patching Up) - Run Script'),
+(25849, 0, 3, 0, 40, 2, 100, 0, 11, 25849, 0, 0, 80, 2584901, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Reached WP11 - Run Script (Phase 2)'),
+(25849, 0, 4, 5, 40, 2, 100, 0, 12, 25849, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Reached WP12 - Set Phase 1'),
+(25849, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 4.06662, 'Fezzix Geartwist - - On Reached WP12 - Set Orientation'),
+(2540100, 9, 0, 0, 0, 0, 100, 0, 0, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 0'),
+(2540100, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 1'),
+(2540100, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 3, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 5, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 6, 0, 0, 0, 100, 0, 900, 900, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Set Phase 2'),
+(2540100, 9, 7, 0, 0, 0, 100, 0, 100, 100, 0, 0, 11, 45502, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Cast Seaforium Depth Charge Explosion'),
+(2540100, 9, 8, 0, 0, 0, 100, 0, 500, 500, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Cast Seaforium Depth Charge Explosion'),
+(2584900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Set Phase 2'),
+(2584900, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 12, 26040, 1, 13000, 0, 0, 0, 8, 0, 0, 0, 3481.329, 4099.854, 17.83902, 3.351032, 'Fezzix Geartwist - Script - Spawn Fezzixs Flying Machine'),
+(2584900, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60069, 188087, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage A'),
+(2584900, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60080, 188088, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage B'),
+(2584900, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60095, 188089, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage C'),
+(2584900, 9, 5, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Say Line 2'),
+(2584900, 9, 6, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 43, 0, 22719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Mount Display ID 22719'),
+(2584900, 9, 7, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Say Line 3'),
+(2584900, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Set Fly On'),
+(2584900, 9, 9, 0, 0, 0, 100, 0, 0, 0, 0, 0, 53, 0, 25849, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Start WP'),
+(2583400, 9, 0, 0, 0, 0, 100, 0, 500, 500, 0, 0, 11, 34427, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Cast Ethereal Teleport'),
+(2583400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 10, @CGUID+0, 23837, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line on Bunny'),
+(2583400, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 1'),
+(2583400, 9, 3, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Set Orientation'),
+(2583400, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 2'),
+(2583400, 9, 5, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 3'),
+(2583400, 9, 6, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 4'),
+(2583400, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 19, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Remove Unit Flag (Immune to PC)'),
+(2583400, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Start Attack'),
+(2584901, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 46419, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Cast Cosmetic - Explosion'),
+(2584901, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Dismount'),
+(2584901, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Turn Fly Off'),
+(2584901, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 42963, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Cast Cosmetic - Combat Knockdown Self'),
+(2584901, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Say Line 4'),
+(2584901, 9, 5, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Say Line 5'),
+(2598300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Set Phase 2'),
+(2598300, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 11, 46399, 0, 0, 0, 0, 0, 14, 113431, 26041, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Cast Energy Transfer'),
+(2598300, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Set Phase 1'),
+(2560200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Set Phase 2'),
+(2560200, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 11, 28892, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Cast Nature Channeling'),
+(2560200, 9, 2, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 28, 28892, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Remove Aura Nature Channeling'),
+(2560200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Summon Group 0'),
+(2560200, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 1 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 5, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 2 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 6, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 3 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 7, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 4 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 8, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 5, 3, 0, 0, 0, 0, 0, 9, 26097, 0, 200, 0, 0, 0, 0, 'Greatmother Taiga - Script - Play emote OneShotWave on all Fizzcrank Gnome Ghost'),
+(2560200, 9, 9, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 2'),
+(2560200, 9, 10, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Set Phase 1');
+
+
+DELETE FROM `creature_summon_groups` WHERE `summonerId`=25602;
+INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`) VALUES
+(25602, 0, 0, 26097, 3483.047, 4114.145, 18.48475, 3.193953, 1, 40000),
+(25602, 0, 0, 26097, 3486.638, 4116.401, 18.48475, 3.403392, 1, 40000),
+(25602, 0, 0, 26097, 3483.65, 4112.257, 18.48475, 2.9147, 1, 40000),
+(25602, 0, 0, 26097, 3481.733, 4118.205, 18.48475, 3.926991, 1, 40000),
+(25602, 0, 0, 26097, 3485.337, 4117.493, 18.48475, 3.543018, 1, 40000),
+(25602, 0, 0, 26097, 3482.166, 4116.395, 18.48475, 3.612832, 1, 40000),
+(25602, 0, 0, 26097, 3485.657, 4113.342, 18.48475, 3.124139, 1, 40000),
+(25602, 0, 0, 26097, 3483.949, 4118.282, 18.48475, 3.682645, 1, 40000),
+(25602, 0, 0, 26097, 3484.028, 4115.051, 18.48475, 3.316126, 1, 40000),
+(25602, 0, 0, 26097, 3484.057, 4116.235, 18.48474, 3.560472, 1, 40000);
+
+
+DELETE FROM `waypoints` WHERE `entry` =25849;
+
+INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES
+(25849, 1,3476.835, 4099.595, 20.46597, 'Fezzix Geartwist'),
+(25849, 2,3469.259, 4098.425, 23.37573, 'Fezzix Geartwist'),
+(25849, 3,3464.057, 4092.921, 28.09206, 'Fezzix Geartwist'),
+(25849, 4,3468.28, 4083.907, 34.53652, 'Fezzix Geartwist'),
+(25849, 5,3471.045, 4079.119, 38.06437, 'Fezzix Geartwist'),
+(25849, 6,3476.159, 4076.131, 41.48104, 'Fezzix Geartwist'),
+(25849, 7,3483.686, 4077.679, 42.78663, 'Fezzix Geartwist'),
+(25849, 8,3487.812, 4082.535, 42.78663, 'Fezzix Geartwist'),
+(25849, 9,3488.05, 4090.021, 42.78663, 'Fezzix Geartwist'),
+(25849, 10,3486.571, 4098.099, 42.78663, 'Fezzix Geartwist'),
+(25849, 11,3479.899, 4100.219, 42.78663, 'Fezzix Geartwist'),
+(25849, 12,3477.16, 4103.97, 17.9091, 'Fezzix Geartwist');
+
+DELETE FROM `creature` WHERE `guid`=@CGUID+0;
+INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES
+(@CGUID+0, 23837, 571, 1, 1, 4000.194, 4853.576, 26.05447, 5.585053, 120, 0, 0); -- 23837 (Area: 3537)
+
+DELETE FROM `event_scripts` WHERE `id`=17209;
+INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES
+(17209, 3, 10, 25834, 3000000, 0, 4004.175, 4850.362, 26.05081,2.391101);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=45502;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 2, 45502, 0, 0, 31, 0, 3, 25402, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (South)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25403, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (East)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25404, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (West)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25405, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (North)');
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=25401;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(22, 3, 25401, 0, 0, 29, 1, 25402, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (South) within 20 yards'),
+(22, 4, 25401, 0, 0, 29, 1, 25403, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (East) within 20 yards'),
+(22, 5, 25401, 0, 0, 29, 1, 25404, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (West) within 20 yards'),
+(22, 6, 25401, 0, 0, 29, 1, 25405, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (North) within 20 yards');
diff --git a/sql/updates/world/2014_09_09_01_world_sai.sql b/sql/updates/world/2014_09_09_01_world_sai.sql
new file mode 100644
index 00000000000..b286b0ad03f
--- /dev/null
+++ b/sql/updates/world/2014_09_09_01_world_sai.sql
@@ -0,0 +1,8 @@
+UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` =25969;
+DELETE FROM `smart_scripts` WHERE `entryorguid` =25969 AND `source_type`=0;
+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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(25969, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 11, 46340, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Just Summoned - Cast Crates Carried'),
+(25969, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Just Summoned - Set Passive'),
+(25969, 0, 2, 0, 32, 0, 100, 0, 50, 20000, 3000, 5000, 11, 46342, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Damage - Cast Drop Crate'),
+(25969, 0, 3, 0, 23, 0, 100, 0, 46340, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Has No Aura (Crates Carried) - Despawn'),
+(25969, 0, 4, 0, 75, 0, 100, 0, 0, 25849, 30, 0, 11, 46358, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Jenny - Within 30 yards of Fezzix Geartwist - Give Kill credit');
diff --git a/sql/updates/world/2014_09_09_03_world_misc.sql b/sql/updates/world/2014_09_09_03_world_misc.sql
new file mode 100644
index 00000000000..0936e6087a0
--- /dev/null
+++ b/sql/updates/world/2014_09_09_03_world_misc.sql
@@ -0,0 +1,14 @@
+DELETE FROM `creature_text` WHERE `entry` =19228 AND `groupid`IN(47,48);
+DELETE FROM `creature_text` WHERE `entry` =19228 AND `groupid`=0 AND `id`=4;
+
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(19228, 0, 4, 'Whoa! Is all that applause for me? Thanks for coming out!', 12, 0, 100, 6, 0, 0, 'Perry Gatner',16326),
+(19228, 47, 0, 'Used to be you couldn''t trust a goblin...', 12, 0, 100, 1, 0, 0, 'Perry Gatner',16671),
+(19228, 48, 0, 'Who am I kiddin''? If you trade with goblins you''d better have iron plating in your coinpurse.', 12, 0, 100, 6, 0, 0, 'Perry Gatner',16672);
+
+DELETE FROM `smart_scripts` WHERE `entryorguid`=1927115 AND `source_type`=9;
+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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(1927115, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 47, 0, 0, 0, 0, 0, 19, 19228, 0, 0, 0, 0, 0, 0, 'Albert Quarksprocket - - Script 15 - Say Line 47 (Perry Gatner'),
+(1927115, 9, 1, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 48, 0, 0, 0, 0, 0, 19, 19228, 0, 0, 0, 0, 0, 0, 'Albert Quarksprocket - - Script 15 - Say Line 48 (Perry Gatner');
+
+UPDATE `smart_scripts` SET `action_param3`=192715 WHERE `entryorguid`=19271 AND `source_type`=0 AND `id`=13;
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index f26c0342654..01dbaa6aa9a 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -118,7 +118,8 @@ int main(int argc, char** argv)
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port);
+ AsyncAcceptor authServer(_ioService, bindIp, port);
+ authServer.AsyncAccept<AuthSession>();
// Set signal handlers
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index 8276183fb10..e8241ac49b1 100644
--- a/src/server/authserver/Server/AuthSession.cpp
+++ b/src/server/authserver/Server/AuthSession.cpp
@@ -53,6 +53,7 @@ enum eStatus
typedef struct AUTH_LOGON_CHALLENGE_C
{
+ uint8 cmd;
uint8 error;
uint16 size;
uint8 gamename[4];
@@ -71,6 +72,7 @@ typedef struct AUTH_LOGON_CHALLENGE_C
typedef struct AUTH_LOGON_PROOF_C
{
+ uint8 cmd;
uint8 A[32];
uint8 M1[20];
uint8 crc_hash[20];
@@ -98,6 +100,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
typedef struct AUTH_RECONNECT_PROOF_C
{
+ uint8 cmd;
uint8 R1[16];
uint8 R2[20];
uint8 R3[20];
@@ -112,79 +115,88 @@ enum class BufferSizes : uint32
SRP_6_S = 0x20,
};
-#define REALM_LIST_PACKET_SIZE 4
-#define XFER_ACCEPT_SIZE 0
-#define XFER_RESUME_SIZE 8
-#define XFER_CANCEL_SIZE 0
+#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4
+#define REALM_LIST_PACKET_SIZE 5
+#define XFER_ACCEPT_SIZE 1
+#define XFER_RESUME_SIZE 9
+#define XFER_CANCEL_SIZE 1
std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
{
std::unordered_map<uint8, AuthHandler> handlers;
- handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleLogonChallenge };
- handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
- handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleReconnectChallenge };
- handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
- handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };
- handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept };
- handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume };
- handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel };
+ handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge };
+ handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
+ handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge };
+ handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
+ handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };
+ handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept };
+ handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume };
+ handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel };
return handlers;
}
std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers();
-void AuthSession::ReadHeaderHandler()
+void AuthSession::ReadHandler()
{
- uint8 cmd = GetHeaderBuffer()[0];
- auto itr = Handlers.find(cmd);
- if (itr != Handlers.end())
+ MessageBuffer& packet = GetReadBuffer();
+ while (packet.GetActiveSize())
{
- // Handle dynamic size packet
+ uint8 cmd = packet.GetReadPointer()[0];
+ auto itr = Handlers.find(cmd);
+ if (itr == Handlers.end())
+ {
+ // well we dont handle this, lets just ignore it
+ packet.Reset();
+ break;
+ }
+
+ uint16 size = uint16(itr->second.packetSize);
+ if (packet.GetActiveSize() < size)
+ break;
+
if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE)
{
- ReadData(sizeof(uint8) + sizeof(uint16)); //error + size
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(packet.GetReadPointer());
+ size += challenge->size;
+ }
- AsyncReadData(challenge->size);
+ if (packet.GetActiveSize() < size)
+ break;
+
+ if (!(*this.*Handlers.at(cmd).handler)())
+ {
+ CloseSocket();
+ return;
}
- else
- AsyncReadData(itr->second.packetSize);
- }
- else
- CloseSocket();
-}
-void AuthSession::ReadDataHandler()
-{
- if (!(*this.*Handlers.at(GetHeaderBuffer()[0]).handler)())
- {
- CloseSocket();
- return;
+ packet.ReadCompleted(size);
}
- AsyncReadHeader();
+ AsyncRead();
}
-void AuthSession::AsyncWrite(ByteBuffer& packet)
+void AuthSession::SendPacket(ByteBuffer& packet)
{
if (!IsOpen())
return;
- std::lock_guard<std::mutex> guard(_writeLock);
-
- bool needsWriteStart = _writeQueue.empty();
+ if (!packet.empty())
+ {
+ MessageBuffer buffer;
+ buffer.Write(packet.contents(), packet.size());
- _writeQueue.push(std::move(packet));
+ std::unique_lock<std::mutex> guard(_writeLock);
- if (needsWriteStart)
- Base::AsyncWrite(_writeQueue.front());
+ QueuePacket(std::move(buffer), guard);
+ }
}
bool AuthSession::HandleLogonChallenge()
{
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
@@ -393,7 +405,7 @@ bool AuthSession::HandleLogonChallenge()
pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
}
- AsyncWrite(pkt);
+ SendPacket(pkt);
return true;
}
@@ -403,7 +415,7 @@ bool AuthSession::HandleLogonProof()
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
// Read the packet
- sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetDataBuffer());
+ sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer());
// If the client has no valid version
if (_expversion == NO_VALID_EXP_FLAG)
@@ -515,10 +527,9 @@ bool AuthSession::HandleLogonProof()
// Check auth token
if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
{
- ReadData(1);
- uint8 size = *(GetDataBuffer() + sizeof(sAuthLogonProof_C));
- ReadData(size);
- std::string token(reinterpret_cast<char*>(GetDataBuffer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size);
+ uint8 size = *(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C));
+ std::string token(reinterpret_cast<char*>(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size);
+ GetReadBuffer().ReadCompleted(sizeof(size) + size);
uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str());
uint32 incomingToken = atoi(token.c_str());
if (validToken != incomingToken)
@@ -528,7 +539,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
packet << uint8(3);
packet << uint8(0);
- AsyncWrite(packet);
+ SendPacket(packet);
return false;
}
}
@@ -559,7 +570,7 @@ bool AuthSession::HandleLogonProof()
std::memcpy(packet.contents(), &proof, sizeof(proof));
}
- AsyncWrite(packet);
+ SendPacket(packet);
_isAuthenticated = true;
}
else
@@ -569,7 +580,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
packet << uint8(3);
packet << uint8(0);
- AsyncWrite(packet);
+ SendPacket(packet);
TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str());
@@ -638,7 +649,7 @@ bool AuthSession::HandleLogonProof()
bool AuthSession::HandleReconnectChallenge()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge");
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
@@ -682,14 +693,14 @@ bool AuthSession::HandleReconnectChallenge()
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros
- AsyncWrite(pkt);
+ SendPacket(pkt);
return true;
}
bool AuthSession::HandleReconnectProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
- sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetDataBuffer());
+ sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer());
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
return false;
@@ -710,7 +721,7 @@ bool AuthSession::HandleReconnectProof()
pkt << uint8(AUTH_RECONNECT_PROOF);
pkt << uint8(0x00);
pkt << uint16(0x00); // 2 bytes zeros
- AsyncWrite(pkt);
+ SendPacket(pkt);
_isAuthenticated = true;
return true;
}
@@ -870,7 +881,7 @@ bool AuthSession::HandleRealmList()
hdr << uint16(pkt.size() + RealmListSizeBuffer.size());
hdr.append(RealmListSizeBuffer); // append RealmList's size buffer
hdr.append(pkt); // append realms in the realmlist
- AsyncWrite(hdr);
+ SendPacket(hdr);
return true;
}
diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h
index 3497e3a030c..07af61d9c1d 100644
--- a/src/server/authserver/Server/AuthSession.h
+++ b/src/server/authserver/Server/AuthSession.h
@@ -30,14 +30,12 @@ using boost::asio::ip::tcp;
struct AuthHandler;
-class AuthSession : public Socket<AuthSession, ByteBuffer>
+class AuthSession : public Socket<AuthSession>
{
- typedef Socket<AuthSession, ByteBuffer> Base;
-
public:
static std::unordered_map<uint8, AuthHandler> InitHandlers();
- AuthSession(tcp::socket&& socket) : Socket(std::move(socket), 1),
+ AuthSession(tcp::socket&& socket) : Socket(std::move(socket)),
_isAuthenticated(false), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
@@ -46,15 +44,13 @@ public:
void Start() override
{
- AsyncReadHeader();
+ AsyncRead();
}
- using Base::AsyncWrite;
- void AsyncWrite(ByteBuffer& packet);
+ void SendPacket(ByteBuffer& packet);
protected:
- void ReadHeaderHandler() override;
- void ReadDataHandler() override;
+ void ReadHandler() override;
private:
bool HandleLogonChallenge();
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index ba94a99c8dd..fa1f866120c 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -810,6 +810,9 @@ bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 entry,
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
}
+ if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING)
+ AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
+
return true;
}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 9b332bb5de4..9be71be1eed 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -39,22 +39,23 @@ class WorldSession;
enum CreatureFlagsExtra
{
- CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
- CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
- CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
- CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
- CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
- CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
- CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
- CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
- CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
- CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
- CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
- CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
- CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
- CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
- CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are
- CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000 // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
+ CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
+ CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
+ CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
+ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
+ CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
+ CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
+ CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
+ CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
+ CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
+ CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
+ CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
+ CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
+ CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
+ CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
+ CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are
+ CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
+ CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding
};
#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \
@@ -62,7 +63,7 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
- CREATURE_FLAG_EXTRA_GUARD)
+ CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING)
#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index eceb0a8e7de..c1de3aae7cb 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1054,7 +1054,7 @@ enum TrinityStrings
LANG_COMMAND_UNFREEZE = 5003,
LANG_COMMAND_NO_FROZEN_PLAYERS = 5004,
LANG_COMMAND_LIST_FREEZE = 5005,
- LANG_COMMAND_FROZEN_PLAYERS = 5006,
+ LANG_COMMAND_PERMA_FROZEN_PLAYER = 5006,
LANG_INSTANCE_RAID_GROUP_ONLY = 5007,
LANG_INSTANCE_CLOSED = 5008,
LANG_COMMAND_PLAYED_TO_ALL = 5009,
@@ -1068,7 +1068,7 @@ enum TrinityStrings
LANG_ARENA = 5016,
LANG_RAID = 5017,
//= 5018,
- //= 5019,
+ LANG_COMMAND_TEMP_FROZEN_PLAYER = 5019,
LANG_NPCINFO_PHASEMASK = 5020,
LANG_NPCINFO_ARMOR = 5021,
LANG_CHANNEL_ENABLE_OWNERSHIP = 5022,
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 445e42a7f08..321bc707879 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -227,7 +227,7 @@ void WorldSession::SendPacket(WorldPacket* packet)
sScriptMgr->OnPacketSend(this, *packet);
- m_Socket->AsyncWrite(*packet);
+ m_Socket->SendPacket(*packet);
}
/// Add an incoming packet to the queue
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index ca8e2cd5a34..f8673e5d5b7 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -28,14 +28,14 @@
using boost::asio::ip::tcp;
WorldSocket::WorldSocket(tcp::socket&& socket)
- : Socket(std::move(socket), sizeof(ClientPktHeader)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr)
+ : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr)
{
+ _headerBuffer.Resize(sizeof(ClientPktHeader));
}
void WorldSocket::Start()
{
- sScriptMgr->OnSocketOpen(shared_from_this());
- AsyncReadHeader();
+ AsyncRead();
HandleSendAuthSession();
}
@@ -53,14 +53,69 @@ void WorldSocket::HandleSendAuthSession()
seed2.SetRand(16 * 8);
packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds
- AsyncWrite(packet);
+ SendPacket(packet);
}
-void WorldSocket::ReadHeaderHandler()
+void WorldSocket::ReadHandler()
{
- _authCrypt.DecryptRecv(GetHeaderBuffer(), sizeof(ClientPktHeader));
+ if (!IsOpen())
+ return;
+
+ MessageBuffer& packet = GetReadBuffer();
+ while (packet.GetActiveSize() > 0)
+ {
+ if (_headerBuffer.GetRemainingSpace() > 0)
+ {
+ // need to receive the header
+ std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
+ _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
+ packet.ReadCompleted(readHeaderSize);
+
+ if (_headerBuffer.GetRemainingSpace() > 0)
+ {
+ // Couldn't receive the whole header this time.
+ ASSERT(packet.GetActiveSize() == 0);
+ break;
+ }
+
+ // We just received nice new header
+ if (!ReadHeaderHandler())
+ return;
+ }
+
+ // We have full read header, now check the data payload
+ if (_packetBuffer.GetRemainingSpace() > 0)
+ {
+ // need more data in the payload
+ std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
+ _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
+ packet.ReadCompleted(readDataSize);
+
+ if (_packetBuffer.GetRemainingSpace() > 0)
+ {
+ // Couldn't receive the whole data this time.
+ ASSERT(packet.GetActiveSize() == 0);
+ break;
+ }
+ }
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ // just received fresh new payload
+ if (!ReadDataHandler())
+ return;
+
+ _headerBuffer.Reset();
+ }
+
+ AsyncRead();
+}
+
+bool WorldSocket::ReadHeaderHandler()
+{
+ ASSERT(_headerBuffer.GetActiveSize() == sizeof(ClientPktHeader));
+
+ _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader));
+
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
EndianConvertReverse(header->size);
EndianConvert(header->cmd);
@@ -74,24 +129,26 @@ void WorldSocket::ReadHeaderHandler()
}
else
TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
- GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
+ GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
CloseSocket();
- return;
+ return false;
}
- AsyncReadData(header->size - sizeof(header->cmd));
+ header->size -= sizeof(header->cmd);
+ _packetBuffer.Resize(header->size);
+ return true;
}
-void WorldSocket::ReadDataHandler()
+bool WorldSocket::ReadDataHandler()
{
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
uint16 opcode = uint16(header->cmd);
std::string opcodeName = GetOpcodeNameForLogging(opcode);
- WorldPacket packet(opcode, MoveData());
+ WorldPacket packet(opcode, std::move(_packetBuffer));
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
@@ -122,7 +179,7 @@ void WorldSocket::ReadDataHandler()
{
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
CloseSocket();
- return;
+ return false;
}
// Our Idle timer will reset on any non PING opcodes.
@@ -135,10 +192,10 @@ void WorldSocket::ReadDataHandler()
}
}
- AsyncReadHeader();
+ return true;
}
-void WorldSocket::AsyncWrite(WorldPacket& packet)
+void WorldSocket::SendPacket(WorldPacket& packet)
{
if (!IsOpen())
return;
@@ -150,15 +207,27 @@ void WorldSocket::AsyncWrite(WorldPacket& packet)
ServerPktHeader header(packet.size() + 2, packet.GetOpcode());
- std::lock_guard<std::mutex> guard(_writeLock);
+ std::unique_lock<std::mutex> guard(_writeLock);
- bool needsWriteStart = _writeQueue.empty();
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
- _writeQueue.emplace(header, packet);
+#ifndef BOOST_ASIO_HAS_IOCP
+ if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size())
+ {
+ _writeBuffer.Write(header.header, header.getHeaderLength());
+ if (!packet.empty())
+ _writeBuffer.Write(packet.contents(), packet.size());
+ }
+ else
+#endif
+ {
+ MessageBuffer buffer(header.getHeaderLength() + packet.size());
+ buffer.Write(header.header, header.getHeaderLength());
+ if (!packet.empty())
+ buffer.Write(packet.contents(), packet.size());
- if (needsWriteStart)
- AsyncWrite(_writeQueue.front());
+ QueuePacket(std::move(buffer), guard);
+ }
}
void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
@@ -410,7 +479,7 @@ void WorldSocket::SendAuthResponseError(uint8 code)
WorldPacket packet(SMSG_AUTH_RESPONSE, 1);
packet << uint8(code);
- AsyncWrite(packet);
+ SendPacket(packet);
}
void WorldSocket::HandlePing(WorldPacket& recvPacket)
@@ -471,12 +540,5 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
WorldPacket packet(SMSG_PONG, 4);
packet << ping;
- return AsyncWrite(packet);
-}
-
-void WorldSocket::CloseSocket()
-{
- sScriptMgr->OnSocketClose(shared_from_this());
-
- Socket::CloseSocket();
+ return SendPacket(packet);
}
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index 0667c1b090a..d301e239340 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -19,16 +19,6 @@
#ifndef __WORLDSOCKET_H__
#define __WORLDSOCKET_H__
-// Forward declare buffer function here - Socket.h must know about it
-struct WorldPacketBuffer;
-namespace boost
-{
- namespace asio
- {
- WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf);
- }
-}
-
#include "Common.h"
#include "AuthCrypt.h"
#include "ServerPktHeader.h"
@@ -54,50 +44,8 @@ struct ClientPktHeader
#pragma pack(pop)
-struct WorldPacketBuffer
+class WorldSocket : public Socket<WorldSocket>
{
- typedef boost::asio::const_buffer value_type;
-
- typedef boost::asio::const_buffer const* const_iterator;
-
- WorldPacketBuffer(ServerPktHeader header, WorldPacket const& packet) : _header(header), _packet(packet)
- {
- _buffers[0] = boost::asio::const_buffer(_header.header, _header.getHeaderLength());
- if (!_packet.empty())
- _buffers[1] = boost::asio::const_buffer(_packet.contents(), _packet.size());
- }
-
- const_iterator begin() const
- {
- return _buffers;
- }
-
- const_iterator end() const
- {
- return _buffers + (_packet.empty() ? 1 : 2);
- }
-
-private:
- boost::asio::const_buffer _buffers[2];
- ServerPktHeader _header;
- WorldPacket _packet;
-};
-
-namespace boost
-{
- namespace asio
- {
- inline WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf)
- {
- return buf;
- }
- }
-}
-
-class WorldSocket : public Socket<WorldSocket, WorldPacketBuffer>
-{
- typedef Socket<WorldSocket, WorldPacketBuffer> Base;
-
public:
WorldSocket(tcp::socket&& socket);
@@ -106,14 +54,12 @@ public:
void Start() override;
- void CloseSocket() override;
-
- using Base::AsyncWrite;
- void AsyncWrite(WorldPacket& packet);
+ void SendPacket(WorldPacket& packet);
protected:
- void ReadHeaderHandler() override;
- void ReadDataHandler() override;
+ void ReadHandler() override;
+ bool ReadHeaderHandler();
+ bool ReadDataHandler();
private:
void HandleSendAuthSession();
@@ -129,6 +75,9 @@ private:
uint32 _OverSpeedPings;
WorldSession* _worldSession;
+
+ MessageBuffer _headerBuffer;
+ MessageBuffer _packetBuffer;
};
#endif
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
new file mode 100644
index 00000000000..21f62fa265c
--- /dev/null
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Config.h"
+#include "NetworkThread.h"
+#include "ScriptMgr.h"
+#include "WorldSocket.h"
+#include "WorldSocketMgr.h"
+#include <boost/system/error_code.hpp>
+
+static void OnSocketAccept(tcp::socket&& sock)
+{
+ sWorldSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+class WorldSocketThread : public NetworkThread<WorldSocket>
+{
+public:
+ void SocketAdded(std::shared_ptr<WorldSocket> sock) override
+ {
+ sScriptMgr->OnSocketOpen(sock);
+ }
+
+ void SocketRemoved(std::shared_ptr<WorldSocket> sock) override
+ {
+ sScriptMgr->OnSocketClose(sock);
+ }
+};
+
+WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m_SockOutUBuff(65536), _tcpNoDelay(true)
+{
+}
+
+bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
+{
+ _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
+
+ TC_LOG_DEBUG("misc", "Max allowed socket connections %d", boost::asio::socket_base::max_connections);
+
+ // -1 means use default
+ _socketSendBufferSize = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
+
+ m_SockOutUBuff = sConfigMgr->GetIntDefault("Network.OutUBuff", 65536);
+
+ if (m_SockOutUBuff <= 0)
+ {
+ TC_LOG_ERROR("misc", "Network.OutUBuff is wrong in your config file");
+ return false;
+ }
+
+ BaseSocketMgr::StartNetwork(service, bindIp, port);
+
+ _acceptor->AsyncAcceptManaged(&OnSocketAccept);
+
+ sScriptMgr->OnNetworkStart();
+ return true;
+}
+
+void WorldSocketMgr::StopNetwork()
+{
+ BaseSocketMgr::StopNetwork();
+
+ sScriptMgr->OnNetworkStop();
+}
+
+void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock)
+{
+ // set some options here
+ if (_socketSendBufferSize >= 0)
+ {
+ boost::system::error_code err;
+ sock.set_option(boost::asio::socket_base::send_buffer_size(_socketSendBufferSize), err);
+ if (err && err != boost::system::errc::not_supported)
+ {
+ TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen sock.set_option(boost::asio::socket_base::send_buffer_size) err = %s", err.message().c_str());
+ return;
+ }
+ }
+
+ // Set TCP_NODELAY.
+ if (_tcpNoDelay)
+ {
+ boost::system::error_code err;
+ sock.set_option(boost::asio::ip::tcp::no_delay(true), err);
+ if (err)
+ {
+ TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen sock.set_option(boost::asio::ip::tcp::no_delay) err = %s", err.message().c_str());
+ return;
+ }
+ }
+
+ //sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff);
+
+ BaseSocketMgr::OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+NetworkThread<WorldSocket>* WorldSocketMgr::CreateThreads() const
+{
+ return new WorldSocketThread[GetNetworkThreadCount()];
+}
diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h
new file mode 100644
index 00000000000..92a28d0c135
--- /dev/null
+++ b/src/server/game/Server/WorldSocketMgr.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \addtogroup u2w User to World Communication
+ * @{
+ * \file WorldSocketMgr.h
+ * \author Derex <derex101@gmail.com>
+ */
+
+#ifndef __WORLDSOCKETMGR_H
+#define __WORLDSOCKETMGR_H
+
+#include "SocketMgr.h"
+
+class WorldSocket;
+
+/// Manages all sockets connected to peers and network threads
+class WorldSocketMgr : public SocketMgr<WorldSocket>
+{
+ typedef SocketMgr<WorldSocket> BaseSocketMgr;
+
+public:
+ static WorldSocketMgr& Instance()
+ {
+ static WorldSocketMgr instance;
+ return instance;
+ }
+
+ /// Start network, listen at address:port .
+ bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override;
+
+ /// Stops all network threads, It will wait for all running threads .
+ void StopNetwork() override;
+
+ void OnSocketOpen(tcp::socket&& sock) override;
+
+protected:
+ WorldSocketMgr();
+
+ NetworkThread<WorldSocket>* CreateThreads() const override;
+
+private:
+ int32 _socketSendBufferSize;
+ int32 m_SockOutUBuff;
+ bool _tcpNoDelay;
+};
+
+#define sWorldSocketMgr WorldSocketMgr::Instance()
+
+#endif
+/// @}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5c65055f3c0..58e3cffa8de 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -856,6 +856,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_GM_VISIBLE_STATE] = sConfigMgr->GetIntDefault("GM.Visible", 2);
m_int_configs[CONFIG_GM_CHAT] = sConfigMgr->GetIntDefault("GM.Chat", 2);
m_int_configs[CONFIG_GM_WHISPERING_TO] = sConfigMgr->GetIntDefault("GM.WhisperingTo", 2);
+ m_int_configs[CONFIG_GM_FREEZE_DURATION] = sConfigMgr->GetIntDefault("GM.FreezeAuraDuration", 0);
m_int_configs[CONFIG_GM_LEVEL_IN_GM_LIST] = sConfigMgr->GetIntDefault("GM.InGMList.Level", SEC_ADMINISTRATOR);
m_int_configs[CONFIG_GM_LEVEL_IN_WHO_LIST] = sConfigMgr->GetIntDefault("GM.InWhoList.Level", SEC_ADMINISTRATOR);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 05bfcc21462..cc2078bc736 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -227,6 +227,7 @@ enum WorldIntConfigs
CONFIG_GM_ACCEPT_TICKETS,
CONFIG_GM_CHAT,
CONFIG_GM_WHISPERING_TO,
+ CONFIG_GM_FREEZE_DURATION,
CONFIG_GM_LEVEL_IN_GM_LIST,
CONFIG_GM_LEVEL_IN_WHO_LIST,
CONFIG_START_GM_LEVEL,
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 80b7710cd21..3e7b242f3cc 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -2241,69 +2241,100 @@ public:
static bool HandleFreezeCommand(ChatHandler* handler, char const* args)
{
- std::string name;
- Player* player;
- char const* TargetName = strtok((char*)args, " "); // get entered name
- if (!TargetName) // if no name entered use target
- {
- player = handler->getSelectedPlayer();
- if (player) //prevent crash with creature as target
- {
- name = player->GetName();
- normalizePlayerName(name);
- }
- }
- else // if name entered
+ Player* player = handler->getSelectedPlayer(); // Selected player, if any. Might be null.
+ uint32 freezeDuration = 0; // Freeze Duration (in seconds)
+ bool canApplyFreeze = false; // Determines if every possible argument is set so Freeze can be applied
+ bool getDurationFromConfig = false; // If there's no given duration, we'll retrieve the world cfg value later
+
+ /*
+ Possible Freeze Command Scenarios:
+ case 1 - .freeze (without args and a selected player)
+ case 2 - .freeze duration (with a selected player)
+ case 3 - .freeze player duration
+ case 4 - .freeze player (without specifying duration)
+ */
+
+ // case 1: .freeze
+ if (!*args)
{
- name = TargetName;
- normalizePlayerName(name);
- player = sObjectAccessor->FindPlayerByName(name);
+ // Might have a selected player. We'll check it later
+ // Get the duration from world cfg
+ getDurationFromConfig = true;
}
-
- if (!player)
+ else
{
- handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
- return true;
+ // Get the args that we might have (up to 2)
+ char const* arg1 = strtok((char*)args, " ");
+ char const* arg2 = strtok(NULL, " ");
+
+ // Analyze them to see if we got either a playerName or duration or both
+ if (arg1)
+ {
+ if (isNumeric(arg1))
+ {
+ // case 2: .freeze duration
+ // We have a selected player. We'll check him later
+ freezeDuration = uint32(atoi(arg1));
+ canApplyFreeze = true;
+ }
+ else
+ {
+ // case 3 or 4: .freeze player duration | .freeze player
+ // find the player
+ std::string name = arg1;
+ normalizePlayerName(name);
+ player = sObjectAccessor->FindPlayerByName(name);
+ // Check if we have duration set
+ if (arg2 && isNumeric(arg2))
+ {
+ freezeDuration = uint32(atoi(arg2));
+ canApplyFreeze = true;
+ }
+ else
+ getDurationFromConfig = true;
+ }
+ }
}
- if (player == handler->GetSession()->GetPlayer())
+ // Check if duration needs to be retrieved from config
+ if (getDurationFromConfig)
{
- handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR);
- return true;
+ freezeDuration = sWorld->getIntConfig(CONFIG_GM_FREEZE_DURATION);
+ canApplyFreeze = true;
}
- // effect
- if (player && (player != handler->GetSession()->GetPlayer()))
+ // Player and duration retrieval is over
+ if (canApplyFreeze)
{
- handler->PSendSysMessage(LANG_COMMAND_FREEZE, name.c_str());
-
- // stop combat + make player unattackable + duel stop + stop some spells
- player->setFaction(35);
- player->CombatStop();
- if (player->IsNonMeleeSpellCast(true))
- player->InterruptNonMeleeSpells(true);
- player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
-
- // if player class = hunter || warlock remove pet if alive
- if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK))
+ if (!player) // can be null if some previous selection failed
+ {
+ handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
+ return true;
+ }
+ else if (player == handler->GetSession()->GetPlayer())
+ {
+ // Can't freeze himself
+ handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR);
+ return true;
+ }
+ else // Apply the effect
{
- if (Pet* pet = player->GetPet())
+ // Add the freeze aura and set the proper duration
+ // Player combat status and flags are now handled
+ // in Freeze Spell AuraScript (OnApply)
+ Aura* freeze = player->AddAura(9454, player);
+ if (freeze)
{
- pet->SavePetToDB(PET_SAVE_AS_CURRENT);
- // not let dismiss dead pet
- if (pet->IsAlive())
- player->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
+ if (freezeDuration)
+ freeze->SetDuration(freezeDuration * IN_MILLISECONDS);
+ handler->PSendSysMessage(LANG_COMMAND_FREEZE, player->GetName().c_str());
+ // save player
+ player->SaveToDB();
+ return true;
}
}
-
- if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(9454))
- Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, player, player);
-
- // save player
- player->SaveToDB();
}
-
- return true;
+ return false;
}
static bool HandleUnFreezeCommand(ChatHandler* handler, char const*args)
@@ -2329,15 +2360,10 @@ public:
{
handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str());
- // Reset player faction + allow combat + allow duels
- player->setFactionForRace(player->getRace());
- player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
-
// Remove Freeze spell (allowing movement and spells)
+ // Player Flags + Neutral faction removal is now
+ // handled on the Freeze Spell AuraScript (OnRemove)
player->RemoveAurasDueToSpell(9454);
-
- // Save player
- player->SaveToDB();
}
else
{
@@ -2394,7 +2420,17 @@ public:
{
Field* fields = result->Fetch();
std::string player = fields[0].GetString();
- handler->PSendSysMessage(LANG_COMMAND_FROZEN_PLAYERS, player.c_str());
+ int32 remaintime = fields[1].GetInt32();
+ // Save the frozen player to update remaining time in case of future .listfreeze uses
+ // before the frozen state expires
+ if (Player* frozen = sObjectAccessor->FindPlayerByName(player))
+ frozen->SaveToDB();
+ // Notify the freeze duration
+ if (remaintime == -1) // Permanent duration
+ handler->PSendSysMessage(LANG_COMMAND_PERMA_FROZEN_PLAYER, player.c_str());
+ else
+ // show time left (seconds)
+ handler->PSendSysMessage(LANG_COMMAND_TEMP_FROZEN_PLAYER, player.c_str(), remaintime / IN_MILLISECONDS);
}
while (result->NextRow());
diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp
index 347c87b160b..62c85491a20 100644
--- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp
+++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp
@@ -131,21 +131,28 @@ public:
{
boss_onyxiaAI(Creature* creature) : BossAI(creature, DATA_ONYXIA)
{
- Reset();
+ Initialize();
}
- void Reset() override
+ void Initialize()
{
- if (!IsCombatMovementAllowed())
- SetCombatMovement(true);
-
- _Reset();
-
Phase = PHASE_START;
MovePoint = urand(0, 5);
PointData = GetMoveData();
SummonWhelpCount = 0;
+ triggerGUID = 0;
+ tankGUID = 0;
IsMoving = false;
+ }
+
+ void Reset() override
+ {
+ Initialize();
+
+ if (!IsCombatMovementAllowed())
+ SetCombatMovement(true);
+
+ _Reset();
instance->SetData(DATA_ONYXIA_PHASE, Phase);
instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
@@ -153,17 +160,14 @@ public:
void EnterCombat(Unit* /*who*/) override
{
+ _EnterCombat();
Talk(SAY_AGGRO);
- me->SetInCombatWithZone();
-
- events.Reset();
events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 20000));
events.ScheduleEvent(EVENT_TAIL_SWEEP, urand(15000, 20000));
events.ScheduleEvent(EVENT_CLEAVE, urand(2000, 5000));
events.ScheduleEvent(EVENT_WING_BUFFET, urand(10000, 20000));
- instance->SetBossState(DATA_ONYXIA, IN_PROGRESS);
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
@@ -226,11 +230,11 @@ public:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
- if (Creature* trigger = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TRIGGER_GUID)))
+ if (Creature* trigger = ObjectAccessor::GetCreature(*me, triggerGUID))
me->Kill(trigger);
me->SetReactState(REACT_AGGRESSIVE);
// tank selection based on phase one. If tank is not there i take nearest one
- if (Unit* tank = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_TANK_GUID)))
+ if (Unit* tank = ObjectAccessor::GetUnit(*me, tankGUID))
me->GetMotionMaster()->MoveChase(tank);
else if (Unit* newtarget = SelectTarget(SELECT_TARGET_NEAREST, 0))
me->GetMotionMaster()->MoveChase(newtarget);
@@ -246,7 +250,7 @@ public:
me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetFacingTo(me->GetOrientation() + float(M_PI));
if (Creature * trigger = me->SummonCreature(NPC_TRIGGER, MiddleRoomLocation, TEMPSUMMON_CORPSE_DESPAWN))
- instance->SetData64(DATA_TRIGGER_GUID, trigger->GetGUID());
+ triggerGUID = trigger->GetGUID();
me->GetMotionMaster()->MoveTakeoff(11, Phase2Floating);
me->SetSpeed(MOVE_FLIGHT, 1.0f);
Talk(SAY_PHASE_2_TRANS);
@@ -329,7 +333,7 @@ public:
{
SetCombatMovement(false);
Phase = PHASE_BREATH;
- instance->SetData64(DATA_TANK_GUID, me->GetVictim()->GetGUID());
+ tankGUID = me->GetVictim()->GetGUID();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->GetMotionMaster()->MovePoint(10, Phase2Location);
@@ -394,7 +398,7 @@ public:
}
if (!me->isMoving())
- if (Creature* trigger = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TRIGGER_GUID)))
+ if (Creature* trigger = ObjectAccessor::GetCreature(*me, triggerGUID))
me->SetFacingToObject(trigger);
events.Update(diff);
@@ -470,6 +474,8 @@ public:
uint8 Phase;
uint8 MovePoint;
uint8 SummonWhelpCount;
+ uint64 triggerGUID;
+ uint64 tankGUID;
bool IsMoving;
};
diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp
index 61b57d181a3..6aa50e71b17 100644
--- a/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp
+++ b/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp
@@ -54,8 +54,6 @@ public:
SetBossNumber(EncounterCount);
onyxiaGUID = 0;
- triggerGUID = 0;
- tankGUID = 0;
onyxiaLiftoffTimer = 0;
manyWhelpsCounter = 0;
eruptTimer = 0;
@@ -184,12 +182,6 @@ public:
FloorEruptionGUIDQueue.push(data);
eruptTimer = 2500;
break;
- case DATA_TRIGGER_GUID:
- triggerGUID = data;
- break;
- case DATA_TANK_GUID:
- tankGUID = data;
- break;
}
}
@@ -199,13 +191,6 @@ public:
{
case NPC_ONYXIA:
return onyxiaGUID;
- break;
- case DATA_TRIGGER_GUID:
- return triggerGUID;
- break;
- case DATA_TANK_GUID:
- return tankGUID;
- break;
}
return 0;
diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h b/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h
index 0c423f35de6..c31988843fe 100644
--- a/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h
+++ b/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h
@@ -37,9 +37,7 @@ enum Data32
enum Data64
{
DATA_ONYXIA_GUID = 0,
- DATA_FLOOR_ERUPTION_GUID = 1,
- DATA_TRIGGER_GUID = 2,
- DATA_TANK_GUID = 3
+ DATA_FLOOR_ERUPTION_GUID = 1
};
enum OnyxiaPhases
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index ced964048c2..03507c77efb 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -492,6 +492,14 @@ public:
Talk(SAY_TWIGGY_FLATHEAD_OVER);
Reset();
}
+ else if (creature) // Makes BIG WILL attackable.
+ {
+ creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ creature->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ creature->setFaction(14);
+ creature->AI()->AttackStart(warrior);
+ }
}
} else WaveTimer -= diff;
}
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 45b640f27be..f02edbb5584 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -26,7 +26,6 @@ EndScriptData */
/* ContentData
npc_iruk
npc_corastrasza
-npc_jenny
npc_sinkhole_kill_credit
npc_khunok_the_behemoth
npc_nerubar_victim
@@ -407,125 +406,6 @@ public:
};
/*######
-## npc_jenny
-######*/
-
-enum Jenny
-{
- QUEST_LOADER_UP = 11881,
-
- NPC_FEZZIX_GEARTWIST = 25849,
- NPC_JENNY = 25969,
-
- SPELL_GIVE_JENNY_CREDIT = 46358,
- SPELL_CRATES_CARRIED = 46340,
- SPELL_DROP_CRATE = 46342
-};
-
-class npc_jenny : public CreatureScript
-{
-public:
- npc_jenny() : CreatureScript("npc_jenny") { }
-
- struct npc_jennyAI : public ScriptedAI
- {
- npc_jennyAI(Creature* creature) : ScriptedAI(creature)
- {
- setCrateNumber = false;
- }
-
- bool setCrateNumber;
-
- void Reset() override
- {
- if (!setCrateNumber)
- setCrateNumber = true;
-
- me->SetReactState(REACT_PASSIVE);
-
- if (!me->GetOwner())
- return;
-
- switch (me->GetOwner()->ToPlayer()->GetTeamId())
- {
- case TEAM_ALLIANCE:
- me->setFaction(FACTION_ESCORT_A_NEUTRAL_ACTIVE);
- break;
- default:
- case TEAM_HORDE:
- me->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE);
- break;
- }
- }
-
- void DamageTaken(Unit* /*pDone_by*/, uint32& /*uiDamage*/) override
- {
- DoCast(me, SPELL_DROP_CRATE, true);
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (setCrateNumber)
- {
- me->AddAura(SPELL_CRATES_CARRIED, me);
- setCrateNumber = false;
- }
-
- if (!setCrateNumber && !me->HasAura(SPELL_CRATES_CARRIED))
- me->DisappearAndDie();
-
- if (!UpdateVictim())
- return;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_jennyAI(creature);
- }
-};
-
-/*######
-## npc_fezzix_geartwist
-######*/
-
-class npc_fezzix_geartwist : public CreatureScript
-{
-public:
- npc_fezzix_geartwist() : CreatureScript("npc_fezzix_geartwist") { }
-
- struct npc_fezzix_geartwistAI : public ScriptedAI
- {
- npc_fezzix_geartwistAI(Creature* creature) : ScriptedAI(creature) { }
-
- void MoveInLineOfSight(Unit* who) override
-
- {
- ScriptedAI::MoveInLineOfSight(who);
-
- if (who->GetEntry() != NPC_JENNY || !who->HasAura(SPELL_CRATES_CARRIED))
- return;
-
- Unit* owner = who->GetOwner();
- if (!owner || !me->IsWithinDistInMap(who, 10.0f))
- return;
-
- if (Player* player = owner->ToPlayer())
- {
- owner->CastSpell(owner, SPELL_GIVE_JENNY_CREDIT, true); // Maybe is not working.
- player->CompleteQuest(QUEST_LOADER_UP);
- who->ToCreature()->DisappearAndDie();
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_fezzix_geartwistAI(creature);
- }
-};
-
-/*######
## npc_nesingwary_trapper
######*/
@@ -2112,65 +1992,6 @@ public:
};
/*######
-## Quest 11608: Bury Those Cockroaches!
-######*/
-
-enum BuryThoseCockroaches
-{
- // Quest
- QUEST_BURY_THOSE_COCKROACHES = 11608,
-
- // Spells
- SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION = 45502
-
-};
-
-class npc_seaforium_depth_charge : public CreatureScript
-{
-public:
- npc_seaforium_depth_charge() : CreatureScript("npc_seaforium_depth_charge") { }
-
- struct npc_seaforium_depth_chargeAI : public ScriptedAI
- {
- npc_seaforium_depth_chargeAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 uiExplosionTimer;
-
- void Reset() override
- {
- uiExplosionTimer = urand(5000, 10000);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (uiExplosionTimer < diff)
- {
- DoCast(SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION);
- for (uint8 i = 0; i < 4; ++i)
- {
- if (Creature* cCredit = me->FindNearestCreature(25402 + i, 10.0f))//25402-25405 credit markers
- {
- if (Unit* uOwner = me->GetOwner())
- {
- Player* owner = uOwner->ToPlayer();
- if (owner && owner->GetQuestStatus(QUEST_BURY_THOSE_COCKROACHES) == QUEST_STATUS_INCOMPLETE)
- owner->KilledMonsterCredit(cCredit->GetEntry(), cCredit->GetGUID());
- }
- }
- }
- me->Kill(me);
- return;
- } else uiExplosionTimer -= diff;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_seaforium_depth_chargeAI(creature);
- }
-};
-
-/*######
## Help Those That Cannot Help Themselves, Quest 11876
######*/
@@ -2577,8 +2398,6 @@ void AddSC_borean_tundra()
new npc_corastrasza();
new npc_iruk();
new npc_nerubar_victim();
- new npc_jenny();
- new npc_fezzix_geartwist();
new npc_nesingwary_trapper();
new npc_lurgglbr();
new npc_nexus_drake_hatchling();
@@ -2593,7 +2412,6 @@ void AddSC_borean_tundra()
new npc_bonker_togglevolt();
new npc_trapped_mammoth_calf();
new npc_magmoth_crusher();
- new npc_seaforium_depth_charge();
new npc_valiance_keep_cannoneer();
new npc_warmage_coldarra();
new npc_hidden_cultist();
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 84e36b55c2c..e198a6a0c61 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -3609,6 +3609,79 @@ class spell_gen_eject_all_passengers : public SpellScriptLoader
}
};
+enum GMFreeze
+{
+ SPELL_GM_FREEZE = 9454
+};
+
+class spell_gen_gm_freeze : public SpellScriptLoader
+{
+ public:
+ spell_gen_gm_freeze() : SpellScriptLoader("spell_gen_gm_freeze") { }
+
+ class spell_gen_gm_freeze_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_gm_freeze_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GM_FREEZE))
+ return false;
+ return true;
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ // Do what was done before to the target in HandleFreezeCommand
+ if (Player* player = GetTarget()->ToPlayer())
+ {
+ // stop combat + make player unattackable + duel stop + stop some spells
+ player->setFaction(35);
+ player->CombatStop();
+ if (player->IsNonMeleeSpellCast(true))
+ player->InterruptNonMeleeSpells(true);
+ player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+
+ // if player class = hunter || warlock remove pet if alive
+ if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK))
+ {
+ if (Pet* pet = player->GetPet())
+ {
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ // not let dismiss dead pet
+ if (pet->IsAlive())
+ player->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
+ }
+ }
+ }
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ // Do what was done before to the target in HandleUnfreezeCommand
+ if (Player* player = GetTarget()->ToPlayer())
+ {
+ // Reset player faction + allow combat + allow duels
+ player->setFactionForRace(player->getRace());
+ player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ // save player
+ player->SaveToDB();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_gen_gm_freeze_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_gen_gm_freeze_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gen_gm_freeze_AuraScript();
+ }
+};
+
void AddSC_generic_spell_scripts()
{
new spell_gen_absorb0_hitlimit1();
@@ -3689,4 +3762,5 @@ void AddSC_generic_spell_scripts()
new spell_gen_wg_water();
new spell_gen_whisper_gulch_yogg_saron_whisper();
new spell_gen_eject_all_passengers();
+ new spell_gen_gm_freeze();
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 0669d0b84f9..aa584d026fb 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -417,7 +417,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHARACTER_SOCIAL, "DELETE FROM character_social WHERE guid = ? AND friend = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE, "UPDATE character_social SET note = ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remaintime FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH);
diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h
index 64665c2b198..a8b688e6b26 100644
--- a/src/server/shared/Networking/AsyncAcceptor.h
+++ b/src/server/shared/Networking/AsyncAcceptor.h
@@ -23,37 +23,32 @@
using boost::asio::ip::tcp;
-template <class T>
class AsyncAcceptor
{
public:
- AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port) :
- _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)),
- _socket(ioService)
- {
- AsyncAccept();
- };
+ typedef void(*ManagerAcceptHandler)(tcp::socket&& newSocket);
- AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port, bool tcpNoDelay) :
+ AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) :
_acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)),
_socket(ioService)
{
- _acceptor.set_option(boost::asio::ip::tcp::no_delay(tcpNoDelay));
+ boost::system::error_code error;
+ _acceptor.non_blocking(true, error);
+ }
- AsyncAccept();
- };
+ template <class T>
+ void AsyncAccept();
-private:
- void AsyncAccept()
+ void AsyncAcceptManaged(ManagerAcceptHandler mgrHandler)
{
- _acceptor.async_accept(_socket, [this](boost::system::error_code error)
+ _acceptor.async_accept(_socket, [this, mgrHandler](boost::system::error_code error)
{
if (!error)
{
try
{
// this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class
- std::make_shared<T>(std::move(this->_socket))->Start();
+ mgrHandler(std::move(this->_socket));
}
catch (boost::system::system_error const& err)
{
@@ -61,13 +56,36 @@ private:
}
}
- // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face
- this->AsyncAccept();
+ AsyncAcceptManaged(mgrHandler);
});
}
+private:
tcp::acceptor _acceptor;
tcp::socket _socket;
};
+template<class T>
+void AsyncAcceptor::AsyncAccept()
+{
+ _acceptor.async_accept(_socket, [this](boost::system::error_code error)
+ {
+ if (!error)
+ {
+ try
+ {
+ // this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class
+ std::make_shared<T>(std::move(this->_socket))->Start();
+ }
+ catch (boost::system::system_error const& err)
+ {
+ TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ }
+ }
+
+ // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face
+ this->AsyncAccept<T>();
+ });
+}
+
#endif /* __ASYNCACCEPT_H_ */
diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h
index c7f8ba31a71..2115bea3f47 100644
--- a/src/server/shared/Networking/MessageBuffer.h
+++ b/src/server/shared/Networking/MessageBuffer.h
@@ -26,42 +26,74 @@ class MessageBuffer
typedef std::vector<uint8>::size_type size_type;
public:
- MessageBuffer() : _wpos(0), _storage() { }
+ MessageBuffer() : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(4096);
+ }
- MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _storage(right._storage) { }
+ explicit MessageBuffer(std::size_t initialSize) : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(initialSize);
+ }
+
+ MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right._storage)
+ {
+ }
- MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _storage(right.Move()) { }
+ MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right.Move()) { }
void Reset()
{
- _storage.clear();
_wpos = 0;
+ _rpos = 0;
}
- bool IsMessageReady() const { return _wpos == _storage.size(); }
+ void Resize(size_type bytes)
+ {
+ _storage.resize(bytes);
+ }
- size_type GetSize() const { return _storage.size(); }
+ uint8* GetBasePointer() { return _storage.data(); }
- size_type GetReadyDataSize() const { return _wpos; }
+ uint8* GetReadPointer() { return &_storage[_rpos]; }
- size_type GetMissingSize() const { return _storage.size() - _wpos; }
+ uint8* GetWritePointer() { return &_storage[_wpos]; }
- uint8* Data() { return _storage.data(); }
+ void ReadCompleted(size_type bytes) { _rpos += bytes; }
- void Grow(size_type bytes)
- {
- _storage.resize(_storage.size() + bytes);
- }
+ void WriteCompleted(size_type bytes) { _wpos += bytes; }
- uint8* GetWritePointer() { return &_storage[_wpos]; }
+ size_type GetActiveSize() const { return _wpos - _rpos; }
- void WriteCompleted(size_type bytes) { _wpos += bytes; }
+ size_type GetRemainingSpace() const { return _storage.size() - _wpos; }
+
+ size_type GetBufferSize() const { return _storage.size(); }
+
+ // Discards inactive data
+ void Normalize()
+ {
+ if (_rpos)
+ {
+ if (_rpos != _wpos)
+ memmove(GetBasePointer(), GetReadPointer(), GetActiveSize());
+ _wpos -= _rpos;
+ _rpos = 0;
+ }
+ }
- void ResetWritePointer() { _wpos = 0; }
+ void Write(void* data, std::size_t size)
+ {
+ if (size)
+ {
+ memcpy(GetWritePointer(), data, size);
+ WriteCompleted(size);
+ }
+ }
std::vector<uint8>&& Move()
{
_wpos = 0;
+ _rpos = 0;
return std::move(_storage);
}
@@ -70,6 +102,7 @@ public:
if (this != &right)
{
_wpos = right._wpos;
+ _rpos = right._rpos;
_storage = right._storage;
}
@@ -81,6 +114,7 @@ public:
if (this != &right)
{
_wpos = right._wpos;
+ _rpos = right._rpos;
_storage = right.Move();
}
@@ -89,6 +123,7 @@ public:
private:
size_type _wpos;
+ size_type _rpos;
std::vector<uint8> _storage;
};
diff --git a/src/server/shared/Networking/NetworkThread.h b/src/server/shared/Networking/NetworkThread.h
new file mode 100644
index 00000000000..5ed7f25ed77
--- /dev/null
+++ b/src/server/shared/Networking/NetworkThread.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NetworkThread_h__
+#define NetworkThread_h__
+
+#include "Define.h"
+#include "Errors.h"
+#include "Log.h"
+#include "Timer.h"
+#include <atomic>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <thread>
+
+template<class SocketType>
+class NetworkThread
+{
+public:
+ NetworkThread() : _connections(0), _stopped(false), _thread(nullptr)
+ {
+ }
+
+ virtual ~NetworkThread()
+ {
+ Stop();
+ if (_thread)
+ {
+ Wait();
+ delete _thread;
+ }
+ }
+
+ void Stop()
+ {
+ _stopped = true;
+ }
+
+ bool Start()
+ {
+ if (_thread)
+ return false;
+
+ _thread = new std::thread(&NetworkThread::Run, this);
+ return true;
+ }
+
+ void Wait()
+ {
+ ASSERT(_thread);
+
+ _thread->join();
+ delete _thread;
+ _thread = nullptr;
+ }
+
+ int32 GetConnectionCount() const
+ {
+ return _connections;
+ }
+
+ virtual void AddSocket(std::shared_ptr<SocketType> sock)
+ {
+ std::lock_guard<std::mutex> lock(_newSocketsLock);
+
+ ++_connections;
+ _newSockets.insert(sock);
+ SocketAdded(sock);
+ }
+
+protected:
+ virtual void SocketAdded(std::shared_ptr<SocketType> sock) { }
+ virtual void SocketRemoved(std::shared_ptr<SocketType> sock) { }
+
+ void AddNewSockets()
+ {
+ std::lock_guard<std::mutex> lock(_newSocketsLock);
+
+ if (_newSockets.empty())
+ return;
+
+ for (typename SocketSet::const_iterator i = _newSockets.begin(); i != _newSockets.end(); ++i)
+ {
+ if (!(*i)->IsOpen())
+ {
+ SocketRemoved(*i);
+
+ --_connections;
+ }
+ else
+ _Sockets.insert(*i);
+ }
+
+ _newSockets.clear();
+ }
+
+ void Run()
+ {
+ TC_LOG_DEBUG("misc", "Network Thread Starting");
+
+ typename SocketSet::iterator i, t;
+
+ uint32 sleepTime = 10;
+ uint32 tickStart = 0, diff = 0;
+ while (!_stopped)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+
+ tickStart = getMSTime();
+
+ AddNewSockets();
+
+ for (i = _Sockets.begin(); i != _Sockets.end();)
+ {
+ if (!(*i)->Update())
+ {
+ if ((*i)->IsOpen())
+ (*i)->CloseSocket();
+
+ SocketRemoved(*i);
+
+ --_connections;
+ _Sockets.erase(i++);
+ }
+ else
+ ++i;
+ }
+
+ diff = GetMSTimeDiffToNow(tickStart);
+ sleepTime = diff > 10 ? 0 : 10 - diff;
+ }
+
+ TC_LOG_DEBUG("misc", "Network Thread exits");
+ }
+
+private:
+ typedef std::set<std::shared_ptr<SocketType> > SocketSet;
+
+ std::atomic<int32> _connections;
+ std::atomic<bool> _stopped;
+
+ std::thread* _thread;
+
+ SocketSet _Sockets;
+
+ std::mutex _newSocketsLock;
+ SocketSet _newSockets;
+};
+
+#endif // NetworkThread_h__
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index 3bd30bd731b..17f48343485 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -35,32 +35,40 @@ using boost::asio::ip::tcp;
#define READ_BLOCK_SIZE 4096
-template<class T, class PacketType>
+template<class T>
class Socket : public std::enable_shared_from_this<T>
{
- typedef typename std::conditional<std::is_pointer<PacketType>::value, PacketType, PacketType const&>::type WritePacketType;
-
public:
- Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
- _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false), _closing(false)
+ explicit Socket(tcp::socket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
+ _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false)
{
- _readHeaderBuffer.Grow(headerSize);
+ _readBuffer.Resize(READ_BLOCK_SIZE);
}
virtual ~Socket()
{
boost::system::error_code error;
_socket.close(error);
-
- while (!_writeQueue.empty())
- {
- DeletePacket(_writeQueue.front());
- _writeQueue.pop();
- }
}
virtual void Start() = 0;
+ virtual bool Update()
+ {
+ if (!IsOpen())
+ return false;
+
+#ifndef BOOST_ASIO_HAS_IOCP
+ if (_isWritingAsync || (!_writeBuffer.GetActiveSize() && _writeQueue.empty()))
+ return true;
+
+ for (; WriteHandler(boost::system::error_code(), 0);)
+ ;
+#endif
+
+ return true;
+ }
+
boost::asio::ip::address GetRemoteIpAddress() const
{
return _remoteAddress;
@@ -71,31 +79,14 @@ public:
return _remotePort;
}
- void AsyncReadHeader()
+ void AsyncRead()
{
if (!IsOpen())
return;
- _readHeaderBuffer.ResetWritePointer();
- _readDataBuffer.Reset();
-
- AsyncReadMissingHeaderData();
- }
-
- void AsyncReadData(std::size_t size)
- {
- if (!IsOpen())
- return;
-
- if (!size)
- {
- // if this is a packet with 0 length body just invoke handler directly
- ReadDataHandler();
- return;
- }
-
- _readDataBuffer.Grow(size);
- AsyncReadMissingData();
+ _readBuffer.Normalize();
+ _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), READ_BLOCK_SIZE),
+ std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
void ReadData(std::size_t size)
@@ -105,13 +96,11 @@ public:
boost::system::error_code error;
- _readDataBuffer.Grow(size);
-
- std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readDataBuffer.GetWritePointer(), size), error);
+ std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readBuffer.GetWritePointer(), size), error);
- _readDataBuffer.WriteCompleted(bytesRead);
+ _readBuffer.WriteCompleted(bytesRead);
- if (error || !_readDataBuffer.IsMessageReady())
+ if (error || bytesRead != size)
{
TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(),
error.message().c_str());
@@ -120,15 +109,19 @@ public:
}
}
- void AsyncWrite(WritePacketType data)
+ void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard)
{
- boost::asio::async_write(_socket, boost::asio::buffer(data), std::bind(&Socket<T, PacketType>::WriteHandler, this->shared_from_this(),
- std::placeholders::_1, std::placeholders::_2));
+
+ _writeQueue.push(std::move(buffer));
+
+#ifdef BOOST_ASIO_HAS_IOCP
+ AsyncProcessQueue(guard);
+#endif
}
bool IsOpen() const { return !_closed && !_closing; }
- virtual void CloseSocket()
+ void CloseSocket()
{
if (_closed.exchange(true))
return;
@@ -143,39 +136,37 @@ public:
/// Marks the socket for closing after write buffer becomes empty
void DelayedCloseSocket() { _closing = true; }
- virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); }
- virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); }
-
- uint8* GetHeaderBuffer() { return _readHeaderBuffer.Data(); }
- uint8* GetDataBuffer() { return _readDataBuffer.Data(); }
-
- size_t GetHeaderSize() const { return _readHeaderBuffer.GetReadyDataSize(); }
- size_t GetDataSize() const { return _readDataBuffer.GetReadyDataSize(); }
-
- MessageBuffer&& MoveHeader() { return std::move(_readHeaderBuffer); }
- MessageBuffer&& MoveData() { return std::move(_readDataBuffer); }
+ MessageBuffer& GetReadBuffer() { return _readBuffer; }
protected:
- virtual void ReadHeaderHandler() = 0;
- virtual void ReadDataHandler() = 0;
-
- std::mutex _writeLock;
- std::queue<PacketType> _writeQueue;
+ virtual void ReadHandler() = 0;
-private:
- void AsyncReadMissingHeaderData()
+ bool AsyncProcessQueue(std::unique_lock<std::mutex>&)
{
- _socket.async_read_some(boost::asio::buffer(_readHeaderBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readHeaderBuffer.GetMissingSize())),
- std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+ if (_isWritingAsync)
+ return true;
+
+ _isWritingAsync = true;
+
+#ifdef BOOST_ASIO_HAS_IOCP
+ MessageBuffer& buffer = _writeQueue.front();
+ _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
+ this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+#else
+ _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandler, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+#endif
+
+ return true;
}
- void AsyncReadMissingData()
- {
- _socket.async_read_some(boost::asio::buffer(_readDataBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readDataBuffer.GetMissingSize())),
- std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
- }
+ std::mutex _writeLock;
+ std::queue<MessageBuffer> _writeQueue;
+#ifndef BOOST_ASIO_HAS_IOCP
+ MessageBuffer _writeBuffer;
+#endif
- void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferredBytes)
+private:
+ void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes)
{
if (error)
{
@@ -183,70 +174,130 @@ private:
return;
}
- _readHeaderBuffer.WriteCompleted(transferredBytes);
- if (!IsHeaderReady())
+ _readBuffer.WriteCompleted(transferredBytes);
+ ReadHandler();
+ }
+
+#ifdef BOOST_ASIO_HAS_IOCP
+
+ void WriteHandler(boost::system::error_code error, std::size_t transferedBytes)
+ {
+ if (!error)
{
- // incomplete, read more
- AsyncReadMissingHeaderData();
- return;
- }
+ std::unique_lock<std::mutex> deleteGuard(_writeLock);
+
+ _isWritingAsync = false;
+ _writeQueue.front().ReadCompleted(transferedBytes);
+ if (!_writeQueue.front().GetActiveSize())
+ _writeQueue.pop();
- ReadHeaderHandler();
+ if (!_writeQueue.empty())
+ AsyncProcessQueue(deleteGuard);
+ else if (_closing)
+ CloseSocket();
+ }
+ else
+ CloseSocket();
}
- void ReadDataHandlerInternal(boost::system::error_code error, size_t transferredBytes)
+#else
+
+ bool WriteHandler(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/)
{
+ std::unique_lock<std::mutex> guard(_writeLock, std::try_to_lock);
+ if (!guard)
+ return false;
+
+ if (!IsOpen())
+ return false;
+
+ std::size_t bytesToSend = _writeBuffer.GetActiveSize();
+
+ if (bytesToSend == 0)
+ return HandleQueue(guard);
+
+ boost::system::error_code error;
+ std::size_t bytesWritten = _socket.write_some(boost::asio::buffer(_writeBuffer.GetReadPointer(), bytesToSend), error);
+
if (error)
{
- CloseSocket();
- return;
- }
+ if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
+ return AsyncProcessQueue(guard);
- _readDataBuffer.WriteCompleted(transferredBytes);
- if (!IsDataReady())
+ return false;
+ }
+ else if (bytesWritten == 0)
+ return false;
+ else if (bytesWritten < bytesToSend) //now n > 0
{
- // incomplete, read more
- AsyncReadMissingData();
- return;
+ _writeBuffer.ReadCompleted(bytesWritten);
+ _writeBuffer.Normalize();
+ return AsyncProcessQueue(guard);
}
- ReadDataHandler();
+ // now bytesWritten == bytesToSend
+ _writeBuffer.Reset();
+
+ return HandleQueue(guard);
}
- void WriteHandler(boost::system::error_code error, size_t /*transferedBytes*/)
+ bool HandleQueue(std::unique_lock<std::mutex>& guard)
{
- if (!error)
+ if (_writeQueue.empty())
+ {
+ _isWritingAsync = false;
+ return false;
+ }
+
+ MessageBuffer& queuedMessage = _writeQueue.front();
+
+ std::size_t bytesToSend = queuedMessage.GetActiveSize();
+
+ boost::system::error_code error;
+ std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);
+
+ if (error)
{
- std::lock_guard<std::mutex> deleteGuard(_writeLock);
+ if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
+ return AsyncProcessQueue(guard);
- DeletePacket(_writeQueue.front());
_writeQueue.pop();
+ return false;
+ }
+ else if (bytesSent == 0)
+ {
+ _writeQueue.pop();
+ return false;
+ }
+ else if (bytesSent < bytesToSend) // now n > 0
+ {
+ queuedMessage.ReadCompleted(bytesSent);
+ return AsyncProcessQueue(guard);
+ }
- if (!_writeQueue.empty())
- AsyncWrite(_writeQueue.front());
- else if (_closing)
- CloseSocket();
+ _writeQueue.pop();
+ if (_writeQueue.empty())
+ {
+ _isWritingAsync = false;
+ return false;
}
- else
- CloseSocket();
- }
- template<typename Q = PacketType>
- typename std::enable_if<std::is_pointer<Q>::value>::type DeletePacket(PacketType& packet) { delete packet; }
+ return true;
+ }
- template<typename Q = PacketType>
- typename std::enable_if<!std::is_pointer<Q>::value>::type DeletePacket(PacketType const& /*packet*/) { }
+#endif
tcp::socket _socket;
boost::asio::ip::address _remoteAddress;
uint16 _remotePort;
- MessageBuffer _readHeaderBuffer;
- MessageBuffer _readDataBuffer;
+ MessageBuffer _readBuffer;
std::atomic<bool> _closed;
std::atomic<bool> _closing;
+
+ bool _isWritingAsync;
};
#endif // __SOCKET_H__
diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h
new file mode 100644
index 00000000000..ed638ab89f3
--- /dev/null
+++ b/src/server/shared/Networking/SocketMgr.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SocketMgr_h__
+#define SocketMgr_h__
+
+#include "AsyncAcceptor.h"
+#include "Config.h"
+#include "Errors.h"
+#include "NetworkThread.h"
+#include <boost/asio/ip/tcp.hpp>
+#include <memory>
+
+using boost::asio::ip::tcp;
+
+template<class SocketType>
+class SocketMgr
+{
+public:
+ virtual ~SocketMgr()
+ {
+ delete[] _threads;
+ }
+
+ virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
+ {
+ _threadCount = sConfigMgr->GetIntDefault("Network.Threads", 1);
+
+ if (_threadCount <= 0)
+ {
+ TC_LOG_ERROR("misc", "Network.Threads is wrong in your config file");
+ return false;
+ }
+
+ _acceptor = new AsyncAcceptor(service, bindIp, port);
+ _threads = CreateThreads();
+
+ ASSERT(_threads);
+
+ for (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Start();
+
+ return true;
+ }
+
+ virtual void StopNetwork()
+ {
+ if (_threadCount != 0)
+ for (size_t i = 0; i < _threadCount; ++i)
+ _threads[i].Stop();
+
+ Wait();
+ }
+
+ void Wait()
+ {
+ if (_threadCount != 0)
+ for (size_t i = 0; i < _threadCount; ++i)
+ _threads[i].Wait();
+ }
+
+ virtual void OnSocketOpen(tcp::socket&& sock)
+ {
+ size_t min = 0;
+
+ for (size_t i = 1; i < _threadCount; ++i)
+ if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount())
+ min = i;
+
+ try
+ {
+ std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock));
+ newSocket->Start();
+
+ _threads[min].AddSocket(newSocket);
+ }
+ catch (boost::system::system_error const& err)
+ {
+ TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ }
+ }
+
+ int32 GetNetworkThreadCount() const { return _threadCount; }
+
+protected:
+ SocketMgr() : _threads(nullptr), _threadCount(1)
+ {
+ }
+
+ virtual NetworkThread<SocketType>* CreateThreads() const = 0;
+
+ AsyncAcceptor* _acceptor;
+ NetworkThread<SocketType>* _threads;
+ int32 _threadCount;
+};
+
+#endif // SocketMgr_h__
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index e149902af02..191e44b3e93 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -46,6 +46,7 @@
#include "CliRunnable.h"
#include "SystemConfig.h"
#include "WorldSocket.h"
+#include "WorldSocketMgr.h"
using namespace boost::program_options;
@@ -82,7 +83,7 @@ uint32 realmID; ///< Id of the realm
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void FreezeDetectorHandler(const boost::system::error_code& error);
-AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService);
+AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService);
bool StartDB();
void StopDB();
void WorldUpdateLoop();
@@ -203,7 +204,7 @@ extern int main(int argc, char** argv)
}
// Start the Remote Access port (acceptor) if enabled
- AsyncAcceptor<RASession>* raAcceptor = nullptr;
+ AsyncAcceptor* raAcceptor = nullptr;
if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
raAcceptor = StartRaSocketAcceptor(_ioService);
@@ -217,11 +218,8 @@ extern int main(int argc, char** argv)
// Launch the worldserver listener socket
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- bool tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
- AsyncAcceptor<WorldSocket> worldAcceptor(_ioService, worldListener, worldPort, tcpNoDelay);
-
- sScriptMgr->OnNetworkStart();
+ sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort);
// Set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
@@ -252,6 +250,8 @@ extern int main(int argc, char** argv)
// unload battleground templates before different singletons destroyed
sBattlegroundMgr->DeleteAllBattlegrounds();
+ sWorldSocketMgr.StopNetwork();
+
sInstanceSaveMgr->Unload();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
@@ -379,12 +379,14 @@ void FreezeDetectorHandler(const boost::system::error_code& error)
}
}
-AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService)
+AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService)
{
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
- return new AsyncAcceptor<RASession>(ioService, raListener, raPort);
+ AsyncAcceptor* acceptor = new AsyncAcceptor(ioService, raListener, raPort);
+ acceptor->AsyncAccept<RASession>();
+ return acceptor;
}
/// Initialize connection to the databases
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index b49f9ebd9ec..3fec13684da 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1548,6 +1548,14 @@ GM.Chat = 2
GM.WhisperingTo = 2
#
+# GM.FreezeAuraDuration
+# Description: Allows to set a default duration to the Freeze Aura
+# applied on players when using the .freeze command
+# Default: 0 - (Original aura duration. Lasts until the .unfreeze command is used)
+# N - (Aura duration if unspecified in .freeze command, in seconds)
+GM.FreezeAuraDuration = 0
+
+#
# GM.InGMList.Level
# Description: Maximum GM level shown in GM list (if enabled) in non-GM state (.gm off).
# Default: 3 - (Anyone)