aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2014-09-12 20:26:46 +0200
committerShauren <shauren.trinity@gmail.com>2014-09-12 20:26:46 +0200
commit7f2cdfd166d99efdd308f0b4d195a6b972092dd9 (patch)
tree8871e168077155d8daabca787b223940f8774af9 /src
parentbe8111b0a21308e78435e9bc20bbbb2804d51c78 (diff)
parent6dff6b74256748f182ad65634a1ab16c5989d40e (diff)
Merge branch 'master' of https://github.com/TrinityCore/TrinityCore into 4.3.4
Conflicts: src/server/authserver/Main.cpp src/server/authserver/Server/AuthSession.cpp src/server/authserver/Server/AuthSession.h src/server/game/Server/WorldSocket.cpp src/server/game/Server/WorldSocket.h src/server/scripts/World/npcs_special.cpp
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/CMakeLists.txt1
-rw-r--r--src/server/authserver/Main.cpp13
-rw-r--r--src/server/authserver/Server/AuthSession.cpp121
-rw-r--r--src/server/authserver/Server/AuthSession.h13
-rw-r--r--src/server/authserver/Server/AuthSocketMgr.h61
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h2
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp7
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp6
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Groups/Group.h14
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp24
-rw-r--r--src/server/game/Loot/LootMgr.cpp7
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSocket.cpp141
-rw-r--r--src/server/game/Server/WorldSocket.h76
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp115
-rw-r--r--src/server/game/Server/WorldSocketMgr.h66
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp130
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp133
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp1
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp6
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp98
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp18
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp142
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp6
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp129
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h70
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp282
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp8
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_eck.cpp146
-rw-r--r--src/server/scripts/Northrend/Gundrak/gundrak.h6
-rw-r--r--src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp21
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp182
-rw-r--r--src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp2
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp1
-rw-r--r--src/server/scripts/Outland/zone_shattrath_city.cpp69
-rw-r--r--src/server/scripts/World/npcs_special.cpp101
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp6
-rw-r--r--src/server/shared/Networking/AsyncAcceptor.h55
-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
48 files changed, 1621 insertions, 1289 deletions
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt
index d6f0515a8e1..d7f1eb4fa30 100644
--- a/src/server/authserver/CMakeLists.txt
+++ b/src/server/authserver/CMakeLists.txt
@@ -44,6 +44,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src/server/shared
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index af7ecd15160..5c06a1e1c34 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -24,23 +24,21 @@
* authentication server
*/
-
-#include "AsyncAcceptor.h"
-#include "AuthSession.h"
+#include "AuthSocketMgr.h"
#include "BattlenetManager.h"
#include "BattlenetSessionManager.h"
#include "Common.h"
-#include "Configuration/Config.h"
-#include "Database/DatabaseEnv.h"
+#include "Config.h"
+#include "DatabaseEnv.h"
#include "Log.h"
#include "ProcessPriority.h"
#include "RealmList.h"
#include "SystemConfig.h"
#include "Util.h"
#include <cstdlib>
+#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>
-#include <iostream>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
@@ -128,9 +126,10 @@ int main(int argc, char** argv)
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port);
AsyncAcceptor<Battlenet::Session> bnetServer(_ioService, bindIp, bnport);
+ sAuthSocketMgr.StartNetwork(_ioService, bindIp, port);
+
// Set signal handlers
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
#if PLATFORM == PLATFORM_WINDOWS
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index 91a2ff9757a..0ba832af483 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)
- AuthSocket::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);
@@ -395,7 +407,7 @@ bool AuthSession::HandleLogonChallenge()
pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
}
- AsyncWrite(pkt);
+ SendPacket(pkt);
return true;
}
@@ -405,7 +417,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)
@@ -512,10 +524,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)
@@ -525,7 +536,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
packet << uint8(3);
packet << uint8(0);
- AsyncWrite(packet);
+ SendPacket(packet);
return false;
}
}
@@ -556,7 +567,7 @@ bool AuthSession::HandleLogonProof()
std::memcpy(packet.contents(), &proof, sizeof(proof));
}
- AsyncWrite(packet);
+ SendPacket(packet);
_isAuthenticated = true;
}
else
@@ -566,7 +577,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());
@@ -635,7 +646,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);
@@ -679,14 +690,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;
@@ -707,7 +718,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;
}
@@ -832,7 +843,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 04ee339df8e..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> AuthSocket;
-
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,14 +44,13 @@ public:
void Start() override
{
- AsyncReadHeader();
+ AsyncRead();
}
- 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/authserver/Server/AuthSocketMgr.h b/src/server/authserver/Server/AuthSocketMgr.h
new file mode 100644
index 00000000000..a14ee26ed56
--- /dev/null
+++ b/src/server/authserver/Server/AuthSocketMgr.h
@@ -0,0 +1,61 @@
+/*
+ * 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 AuthSocketMgr_h__
+#define AuthSocketMgr_h__
+
+#include "SocketMgr.h"
+#include "AuthSession.h"
+
+void OnSocketAccept(tcp::socket&& sock);
+
+class AuthSocketMgr : public SocketMgr<AuthSession>
+{
+ typedef SocketMgr<AuthSession> BaseSocketMgr;
+
+public:
+ static AuthSocketMgr& Instance()
+ {
+ static AuthSocketMgr instance;
+ return instance;
+ }
+
+ bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override
+ {
+ if (!BaseSocketMgr::StartNetwork(service, bindIp, port))
+ return false;
+
+ _acceptor->AsyncAcceptManaged(&OnSocketAccept);
+ return true;
+ }
+
+protected:
+ NetworkThread<AuthSession>* CreateThreads() const override
+ {
+ return new NetworkThread<AuthSession>[1];
+ }
+};
+
+#define sAuthSocketMgr AuthSocketMgr::Instance()
+
+void OnSocketAccept(tcp::socket&& sock)
+{
+ sAuthSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+
+#endif // AuthSocketMgr_h__
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
index 9c9a39cf567..df930367878 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
@@ -72,7 +72,7 @@ class AuctionBotBuyer : public AuctionBotAgent
{
public:
AuctionBotBuyer();
- ~AuctionBotBuyer() override;
+ ~AuctionBotBuyer();
bool Initialize() override;
bool Update(AuctionHouseType houseType) override;
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
index 014fe23f71a..42677a52f49 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
@@ -118,7 +118,7 @@ public:
typedef std::vector<uint32> ItemPool;
AuctionBotSeller();
- ~AuctionBotSeller() override;
+ ~AuctionBotSeller();
bool Initialize() override;
bool Update(AuctionHouseType houseType) override;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ee8fee198bf..bab96b15292 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3878,7 +3878,8 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (!pSkill)
continue;
- if (_spell_idx->second->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id))
+ ///@todo: confirm if rogues start with lockpicking skill at level 1 but only receive the spell to use it at level 16
+ if ((_spell_idx->second->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id)) || (pSkill->id == SKILL_LOCKPICKING && _spell_idx->second->max_value == 0))
LearnDefaultSkill(pSkill->id, 0);
}
}
@@ -17943,6 +17944,7 @@ bool Player::isAllowedToLoot(const Creature* creature)
switch (thisGroup->GetLootMethod())
{
+ case MASTER_LOOT:
case FREE_FOR_ALL:
return true;
case ROUND_ROBIN:
@@ -17952,7 +17954,6 @@ bool Player::isAllowedToLoot(const Creature* creature)
return true;
return loot->hasItemFor(this);
- case MASTER_LOOT:
case GROUP_LOOT:
case NEED_BEFORE_GREED:
// may only loot if the player is the loot roundrobin player
@@ -23664,6 +23665,8 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
skillValue = std::min(std::max<uint16>({ 1, uint16((getLevel() - 1) * 5) }), maxValue);
else if (skillId == SKILL_FIST_WEAPONS)
skillValue = std::max<uint16>(1, GetSkillValue(SKILL_UNARMED));
+ else if (skillId == SKILL_LOCKPICKING)
+ skillValue = std::max<uint16>(1, GetSkillValue(SKILL_LOCKPICKING));
SetSkill(skillId, 0, skillValue, maxValue);
break;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index f6615d67c99..6f37f74b607 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -14108,7 +14108,8 @@ void Unit::SetFeared(bool apply)
}
if (Player* player = ToPlayer())
- player->SetClientControl(this, !apply);
+ if(!player->HasUnitState(UNIT_STATE_POSSESSED))
+ player->SetClientControl(this, !apply);
}
void Unit::SetConfused(bool apply)
@@ -14130,7 +14131,8 @@ void Unit::SetConfused(bool apply)
}
if (Player* player = ToPlayer())
- player->SetClientControl(this, !apply);
+ if (!player->HasUnitState(UNIT_STATE_POSSESSED))
+ player->SetClientControl(this, !apply);
}
bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 638cc19784a..fd89ed80429 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -226,7 +226,7 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup,
void Group::ConvertToLFG()
{
- m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_UNK1);
+ m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_LFG_RESTRICTED);
m_lootMethod = NEED_BEFORE_GREED;
if (!isBGGroup() && !isBFGroup())
{
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 4559c5841ae..84e3a5454cd 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -82,13 +82,15 @@ enum GroupMemberAssignment
enum GroupType
{
- GROUPTYPE_NORMAL = 0x00,
- GROUPTYPE_BG = 0x01,
- GROUPTYPE_RAID = 0x02,
- GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask
- GROUPTYPE_UNK1 = 0x04,
- GROUPTYPE_LFG = 0x08
+ GROUPTYPE_NORMAL = 0x00,
+ GROUPTYPE_BG = 0x01,
+ GROUPTYPE_RAID = 0x02,
+ GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask
+ GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions()
+ GROUPTYPE_LFG = 0x08,
// 0x10, leave/change group?, I saw this flag when leaving group and after leaving BG while in group
+ // GROUPTYPE_ONE_PERSON_PARTY = 0x20, 4.x Script_IsOnePersonParty()
+ // GROUPTYPE_EVERYONE_ASSISTANT = 0x40 4.x Script_IsEveryoneAssistant()
};
enum GroupUpdateFlags
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index cfb7df6c34e..ac18a10c9a9 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -310,10 +310,14 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
-
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, true))
+ {
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
+
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ }
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
@@ -334,10 +338,14 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
-
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, true))
+ {
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
+
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ }
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 60475382d5e..26d348737ab 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -902,8 +902,13 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING;
break;
case MASTER_PERMISSION:
- slot_type = LOOT_SLOT_TYPE_MASTER;
+ {
+ if (lv.viewer->GetGroup() && lv.viewer->GetGroup()->GetMasterLooterGuid() == lv.viewer->GetGUID())
+ slot_type = LOOT_SLOT_TYPE_MASTER;
+ else
+ slot_type = LOOT_SLOT_TYPE_LOCKED;
break;
+ }
case RESTRICTED_PERMISSION:
slot_type = LOOT_SLOT_TYPE_LOCKED;
break;
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index feef22c8a21..6d0ea9ea7a4 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -268,7 +268,7 @@ void WorldSession::SendPacket(WorldPacket* packet, bool forced /*= false*/)
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 9a7b212da04..6cf406f21fa 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -32,19 +32,24 @@ std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CON
std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER");
-WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket), sizeof(ClientPktHeader)),
- _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false)
+
+WorldSocket::WorldSocket(tcp::socket&& socket)
+ : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false)
{
+ _headerBuffer.Resize(sizeof(ClientPktHeader));
}
void WorldSocket::Start()
{
- sScriptMgr->OnSocketOpen(shared_from_this());
+ AsyncRead();
- AsyncReadData(ClientConnectionInitialize.length() + 2 /*sizeof(ClientPktHeader::size)*/ + 1 /*null terminator*/);
+ MessageBuffer initializer;
+ ServerPktHeader header(ServerConnectionInitialize.size(), 0);
+ initializer.Write(header.header, header.getHeaderLength() - 2);
+ initializer.Write((void*)ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length());
- _writeQueue.emplace(ServerConnectionInitialize);
- AsyncWrite(_writeQueue.front());
+ std::unique_lock<std::mutex> dummy(_writeLock, std::defer_lock);
+ QueuePacket(std::move(initializer), dummy);
}
void WorldSocket::HandleSendAuthSession()
@@ -60,14 +65,69 @@ void WorldSocket::HandleSendAuthSession()
packet << uint32(_authSeed);
packet << uint8(1);
- AsyncWrite(packet);
+ SendPacket(packet);
+}
+
+void WorldSocket::ReadHandler()
+{
+ 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;
+ }
+ }
+
+ // just received fresh new payload
+ if (!ReadDataHandler())
+ return;
+
+ _headerBuffer.Reset();
+ }
+
+ AsyncRead();
}
-void WorldSocket::ReadHeaderHandler()
+bool WorldSocket::ReadHeaderHandler()
{
- _authCrypt.DecryptRecv(GetHeaderBuffer(), sizeof(ClientPktHeader));
+ ASSERT(_headerBuffer.GetActiveSize() == sizeof(ClientPktHeader));
+
+ _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader));
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
EndianConvertReverse(header->size);
EndianConvert(header->cmd);
@@ -81,26 +141,28 @@ 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()
{
if (_initialized)
{
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(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());
@@ -129,7 +191,7 @@ void WorldSocket::ReadDataHandler()
packet.rfinish(); // contains uint32 disconnectReason;
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
sScriptMgr->OnPacketReceive(_worldSession, packet);
- return;
+ return true;
case CMSG_ENABLE_NAGLE:
{
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
@@ -144,7 +206,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.
@@ -159,23 +221,23 @@ void WorldSocket::ReadDataHandler()
}
else
{
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetDataBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
- std::string initializer(reinterpret_cast<char const*>(header) + sizeof(header->size));
+ std::string initializer(reinterpret_cast<char const*>(_packetBuffer.GetReadPointer()), header->size);
if (initializer != ClientConnectionInitialize)
{
CloseSocket();
- return;
+ return false;
}
_initialized = true;
HandleSendAuthSession();
}
- AsyncReadHeader();
+ return true;
}
-void WorldSocket::AsyncWrite(WorldPacket& packet)
+void WorldSocket::SendPacket(WorldPacket& packet)
{
if (!IsOpen())
return;
@@ -190,15 +252,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)
@@ -480,7 +554,7 @@ void WorldSocket::SendAuthResponseError(uint8 code)
packet.WriteBit(0); // has account info
packet << uint8(code);
- AsyncWrite(packet);
+ SendPacket(packet);
}
void WorldSocket::HandlePing(WorldPacket& recvPacket)
@@ -541,12 +615,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 9e5f785d939..6ba76584909 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 "WorldPacketCrypt.h"
#include "ServerPktHeader.h"
@@ -54,58 +44,8 @@ struct ClientPktHeader
#pragma pack(pop)
-struct WorldPacketBuffer
-{
- 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), _bufferCount(0)
- {
- _buffers[_bufferCount++] = boost::asio::const_buffer(_header.header, _header.getHeaderLength());
- if (!_packet.empty())
- _buffers[_bufferCount++] = boost::asio::const_buffer(_packet.contents(), _packet.size());
- }
-
- WorldPacketBuffer(std::string const& str) : _header(str.length() + 1 /*null terminator*/, 0), _packet(), _bufferCount(0)
- {
- _buffers[_bufferCount++] = boost::asio::const_buffer(_header.header, _header.getHeaderLength() - 2 /*sizeof(opcode)*/);
- if (!str.empty())
- _buffers[_bufferCount++] = boost::asio::const_buffer(str.c_str(), _header.size);
- }
-
- const_iterator begin() const
- {
- return _buffers;
- }
-
- const_iterator end() const
- {
- return _buffers + _bufferCount;
- }
-
-private:
- boost::asio::const_buffer _buffers[2];
- ServerPktHeader _header;
- WorldPacket _packet;
- uint32 _bufferCount;
-};
-
-namespace boost
-{
- namespace asio
- {
- inline WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf)
- {
- return buf;
- }
- }
-}
-
-class WorldSocket : public Socket<WorldSocket, WorldPacketBuffer>
+class WorldSocket : public Socket<WorldSocket>
{
- typedef Socket<WorldSocket, WorldPacketBuffer> Base;
-
static std::string const ServerConnectionInitialize;
static std::string const ClientConnectionInitialize;
@@ -118,14 +58,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();
@@ -141,6 +79,10 @@ private:
uint32 _OverSpeedPings;
WorldSession* _worldSession;
+
+ MessageBuffer _headerBuffer;
+ MessageBuffer _packetBuffer;
+
bool _initialized;
};
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/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
index ca46ff36079..651e487522d 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
@@ -72,7 +72,7 @@ public:
void Reset() override
{
Initialize();
-
+ events.Reset();
summons.DespawnAll();
}
diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
index 49c5a61b7d0..d9b0c1490b5 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
@@ -30,12 +30,21 @@ enum Spells
SPELL_STORMPIKE = 51876 // not sure
};
-enum Yells
+enum Texts
{
- YELL_AGGRO = 0,
- YELL_EVADE = 1,
- YELL_RESPAWN = 2,
- YELL_RANDOM = 3
+ SAY_AGGRO = 0,
+ SAY_EVADE = 1,
+ SAY_RESPAWN = 2,
+ SAY_RANDOM = 3
+};
+
+enum Events
+{
+ EVENT_WHIRLWIND = 1,
+ EVENT_WHIRLWIND2,
+ EVENT_KNOCKDOWN,
+ EVENT_FRENZY,
+ EVENT_RANDOM_YELL
};
class boss_drekthar : public CreatureScript
@@ -45,92 +54,85 @@ public:
struct boss_drektharAI : public ScriptedAI
{
- boss_drektharAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- WhirlwindTimer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- Whirlwind2Timer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- KnockdownTimer = 12 * IN_MILLISECONDS;
- FrenzyTimer = 6 * IN_MILLISECONDS;
- ResetTimer = 5 * IN_MILLISECONDS;
- YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
- }
-
- uint32 WhirlwindTimer;
- uint32 Whirlwind2Timer;
- uint32 KnockdownTimer;
- uint32 FrenzyTimer;
- uint32 YellTimer;
- uint32 ResetTimer;
+ boss_drektharAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
- Initialize();
+ events.Reset();
}
void EnterCombat(Unit* /*who*/) override
{
- Talk(YELL_AGGRO);
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_KNOCKDOWN, 12 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_FRENZY, 6 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_RANDOM_YELL, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS)); //20 to 30 seconds
}
void JustRespawned() override
{
Reset();
- Talk(YELL_RESPAWN);
+ Talk(SAY_RESPAWN);
}
- void UpdateAI(uint32 diff) override
+ bool CheckInRoom()
{
- if (!UpdateVictim())
- return;
-
- if (WhirlwindTimer <= diff)
+ if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{
- DoCastVictim(SPELL_WHIRLWIND);
- WhirlwindTimer = urand(8 * IN_MILLISECONDS, 18 * IN_MILLISECONDS);
- } else WhirlwindTimer -= diff;
+ EnterEvadeMode();
+ Talk(SAY_EVADE);
+ return false;
+ }
- if (Whirlwind2Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND2);
- Whirlwind2Timer = urand(7 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
- } else Whirlwind2Timer -= diff;
+ return true;
+ }
- if (KnockdownTimer <= diff)
- {
- DoCastVictim(SPELL_KNOCKDOWN);
- KnockdownTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
- } else KnockdownTimer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || !CheckInRoom())
+ return;
- if (FrenzyTimer <= diff)
- {
- DoCastVictim(SPELL_FRENZY);
- FrenzyTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
- } else FrenzyTimer -= diff;
+ events.Update(diff);
- if (YellTimer <= diff)
- {
- Talk(YELL_RANDOM);
- YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
- } else YellTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- // check if creature is not outside of building
- if (ResetTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
+ switch (eventId)
{
- EnterEvadeMode();
- Talk(YELL_EVADE);
+ case EVENT_WHIRLWIND:
+ DoCastVictim(SPELL_WHIRLWIND);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(8 * IN_MILLISECONDS, 18 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND2:
+ DoCastVictim(SPELL_WHIRLWIND2);
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(7 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
+ break;
+ case EVENT_KNOCKDOWN:
+ DoCastVictim(SPELL_KNOCKDOWN);
+ events.ScheduleEvent(EVENT_KNOCKDOWN, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
+ break;
+ case EVENT_FRENZY:
+ DoCastVictim(SPELL_FRENZY);
+ events.ScheduleEvent(EVENT_FRENZY, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ case EVENT_RANDOM_YELL:
+ Talk(SAY_RANDOM);
+ events.ScheduleEvent(EVENT_RANDOM_YELL, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ default:
+ break;
}
- ResetTimer = 5 * IN_MILLISECONDS;
- } else ResetTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
index e422975bd1a..0c029537add 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
@@ -27,11 +27,20 @@ enum Spells
SPELL_MORTAL_STRIKE = 16856
};
-enum Yells
+enum Texts
{
- YELL_AGGRO = 0,
- YELL_EVADE = 1,
- YELL_BUFF = 2
+ SAY_AGGRO = 0,
+ SAY_EVADE = 1,
+ SAY_BUFF = 2
+};
+
+enum Events
+{
+ EVENT_CLEAVE = 1,
+ EVENT_FRIGHTENING_SHOUT,
+ EVENT_WHIRLWIND1,
+ EVENT_WHIRLWIND2,
+ EVENT_MORTAL_STRIKE
};
enum Action
@@ -46,97 +55,85 @@ public:
struct boss_galvangarAI : public ScriptedAI
{
- boss_galvangarAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- CleaveTimer = urand(1 * IN_MILLISECONDS, 9 * IN_MILLISECONDS);
- FrighteningShoutTimer = urand(2 * IN_MILLISECONDS, 19 * IN_MILLISECONDS);
- Whirlwind1Timer = urand(1 * IN_MILLISECONDS, 13 * IN_MILLISECONDS);
- Whirlwind2Timer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- MortalStrikeTimer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- ResetTimer = 5 * IN_MILLISECONDS;
- }
-
- uint32 CleaveTimer;
- uint32 FrighteningShoutTimer;
- uint32 Whirlwind1Timer;
- uint32 Whirlwind2Timer;
- uint32 MortalStrikeTimer;
- uint32 ResetTimer;
+ boss_galvangarAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
- Initialize();
+ events.Reset();
}
void EnterCombat(Unit* /*who*/) override
{
- Talk(YELL_AGGRO);
- }
-
- void JustRespawned() override
- {
- Reset();
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(1 * IN_MILLISECONDS, 9 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(2 * IN_MILLISECONDS, 19 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND1, urand(1 * IN_MILLISECONDS, 13 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_BUFF_YELL)
- Talk(YELL_BUFF);
+ Talk(SAY_BUFF);
}
- void UpdateAI(uint32 diff) override
+ bool CheckInRoom()
{
- if (!UpdateVictim())
- return;
-
- if (CleaveTimer <= diff)
+ if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{
- DoCastVictim(SPELL_CLEAVE);
- CleaveTimer = urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS);
- } else CleaveTimer -= diff;
+ EnterEvadeMode();
+ Talk(SAY_EVADE);
+ return false;
+ }
- if (FrighteningShoutTimer <= diff)
- {
- DoCastVictim(SPELL_FRIGHTENING_SHOUT);
- FrighteningShoutTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
- } else FrighteningShoutTimer -= diff;
+ return true;
+ }
- if (Whirlwind1Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND1);
- Whirlwind1Timer = urand(6 * IN_MILLISECONDS, 10 * IN_MILLISECONDS);
- } else Whirlwind1Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || !CheckInRoom())
+ return;
- if (Whirlwind2Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND2);
- Whirlwind2Timer = urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
- } else Whirlwind2Timer -= diff;
+ events.Update(diff);
- if (MortalStrikeTimer <= diff)
- {
- DoCastVictim(SPELL_MORTAL_STRIKE);
- MortalStrikeTimer = urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
- } else MortalStrikeTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- // check if creature is not outside of building
- if (ResetTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
+ switch (eventId)
{
- EnterEvadeMode();
- Talk(YELL_EVADE);
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS));
+ break;
+ case EVENT_FRIGHTENING_SHOUT:
+ DoCastVictim(SPELL_FRIGHTENING_SHOUT);
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND1:
+ DoCastVictim(SPELL_WHIRLWIND1);
+ events.ScheduleEvent(EVENT_WHIRLWIND1, urand(6 * IN_MILLISECONDS, 10 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND2:
+ DoCastVictim(SPELL_WHIRLWIND2);
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
+ break;
+ case EVENT_MORTAL_STRIKE:
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ default:
+ break;
}
- ResetTimer = 5 * IN_MILLISECONDS;
- } else ResetTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
index b218e3f2978..c5f7a5da6d7 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
@@ -21,7 +21,7 @@
enum Spells
{
SPELL_CURSE_OF_BLOOD = 24673,
- SPELL_ILLUSION = 17773,
+ SPELL_ILLUSION = 17773
};
enum Events
@@ -113,7 +113,7 @@ public:
CreatureAI* GetAI(Creature* creature) const override
{
- return new boss_jandicebarovAI(creature);
+ return GetInstanceAI<boss_jandicebarovAI>(creature);
}
};
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
index 897799a708c..348e2212870 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
@@ -81,7 +81,7 @@ public:
events.ScheduleEvent(EVENT_ICE_ARMOR, 180000);
break;
case EVENT_FROSTBOLT:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
DoCast(target, SPELL_FROSTBOLT);
events.ScheduleEvent(EVENT_FROSTBOLT, 8000);
break;
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
index 792649f2998..dcb212eead8 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
@@ -106,7 +106,6 @@ public:
EventMap events;
};
-
CreatureAI* GetAI(Creature* creature) const override
{
return new boss_vectusAI(creature);
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
index 0a666488e84..fa87247f19f 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
@@ -87,14 +87,14 @@ public:
{
Initialize();
- instance->SetData(DATA_EPOCH_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_EPOCH, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_EPOCH_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_EPOCH, IN_PROGRESS);
}
void UpdateAI(uint32 diff) override
@@ -136,7 +136,7 @@ public:
{
Talk(SAY_DEATH);
- instance->SetData(DATA_EPOCH_EVENT, DONE);
+ instance->SetBossState(DATA_EPOCH, DONE);
}
void KilledUnit(Unit* victim) override
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
index f3333c0b0b6..d693ec38e44 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
@@ -22,7 +22,9 @@
enum Spells
{
SPELL_CORRUPTING_BLIGHT = 60588,
- SPELL_VOID_STRIKE = 60590
+ SPELL_VOID_STRIKE = 60590,
+ SPELL_CORRUPTION_OF_TIME_CHANNEL = 60422,
+ SPELL_CORRUPTION_OF_TIME_TARGET = 60451
};
enum Yells
@@ -32,52 +34,78 @@ enum Yells
SAY_FAIL = 2
};
-class boss_infinite_corruptor : public CreatureScript
+enum Events
{
-public:
- boss_infinite_corruptor() : CreatureScript("boss_infinite_corruptor") { }
+ EVENT_CORRUPTING_BLIGHT = 1,
+ EVENT_VOID_STRIKE
+};
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_infinite_corruptorAI>(creature);
- }
+class boss_infinite_corruptor : public CreatureScript
+{
+ public:
+ boss_infinite_corruptor() : CreatureScript("boss_infinite_corruptor") { }
- struct boss_infinite_corruptorAI : public ScriptedAI
- {
- boss_infinite_corruptorAI(Creature* creature) : ScriptedAI(creature)
+ struct boss_infinite_corruptorAI : public BossAI
{
- instance = creature->GetInstanceScript();
- }
+ boss_infinite_corruptorAI(Creature* creature) : BossAI(creature, DATA_INFINITE) { }
- InstanceScript* instance;
+ void Reset() override
+ {
+ _Reset();
- void Reset() override
- {
- instance->SetData(DATA_INFINITE_EVENT, NOT_STARTED);
- }
+ if (Creature* guardian = me->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ {
+ DoCast((Unit*)NULL, SPELL_CORRUPTION_OF_TIME_CHANNEL, false);
+ guardian->CastSpell(guardian, SPELL_CORRUPTION_OF_TIME_TARGET, false);
+ }
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- instance->SetData(DATA_INFINITE_EVENT, IN_PROGRESS);
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_CORRUPTING_BLIGHT, 7000);
+ events.ScheduleEvent(EVENT_VOID_STRIKE, 5000);
+ }
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
- DoMeleeAttackIfReady();
- }
+ if (Creature* guardian = me->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ {
+ guardian->RemoveAurasDueToSpell(SPELL_CORRUPTION_OF_TIME_TARGET);
+ guardian->DespawnOrUnsummon(5000);
+ }
- void JustDied(Unit* /*killer*/) override
+ if (Creature* rift = me->FindNearestCreature(NPC_TIME_RIFT, 100.0f))
+ rift->DespawnOrUnsummon();
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CORRUPTING_BLIGHT:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
+ DoCast(target, SPELL_CORRUPTING_BLIGHT);
+ events.ScheduleEvent(EVENT_CORRUPTING_BLIGHT, 17000);
+ break;
+ case EVENT_VOID_STRIKE:
+ DoCastVictim(SPELL_VOID_STRIKE);
+ events.ScheduleEvent(EVENT_VOID_STRIKE, 5000);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
{
- Talk(SAY_DEATH);
- instance->SetData(DATA_INFINITE_EVENT, DONE);
+ return GetInstanceAI<boss_infinite_corruptorAI>(creature);
}
- };
-
};
void AddSC_boss_infinite_corruptor()
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
index d9356b724c0..3d1e9363cd8 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
@@ -26,15 +26,13 @@ Script Data End */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "culling_of_stratholme.h"
+#include "Player.h"
enum Spells
{
SPELL_CARRION_SWARM = 52720, //A cresting wave of chaotic magic splashes over enemies in front of the caster, dealing 3230 to 3570 Shadow damage and 380 to 420 Shadow damage every 3 sec. for 15 sec.
- H_SPELL_CARRION_SWARM = 58852,
SPELL_MIND_BLAST = 52722, //Inflicts 4163 to 4837 Shadow damage to an enemy.
- H_SPELL_MIND_BLAST = 58850,
SPELL_SLEEP = 52721, //Puts an enemy to sleep for up to 10 sec. Any damage caused will awaken the target.
- H_SPELL_SLEEP = 58849,
SPELL_VAMPIRIC_TOUCH = 52723, //Heals the caster for half the damage dealt by a melee attack.
SPELL_MAL_GANIS_KILL_CREDIT = 58124, // Quest credit
SPELL_KILL_CREDIT = 58630 // Non-existing spell as encounter credit, created in spell_dbc
@@ -75,7 +73,6 @@ public:
{
Initialize();
instance = creature->GetInstanceScript();
- uiOutroStep = 0;
}
void Initialize()
@@ -108,14 +105,13 @@ public:
void Reset() override
{
Initialize();
-
- instance->SetData(DATA_MAL_GANIS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_MAL_GANIS, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_MAL_GANIS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_MAL_GANIS, IN_PROGRESS);
}
void DamageTaken(Unit* done_by, uint32 &damage) override
@@ -159,7 +155,7 @@ public:
{
EnterEvadeMode();
me->DisappearAndDie();
- instance->SetData(DATA_MAL_GANIS_EVENT, FAIL);
+ instance->SetBossState(DATA_MAL_GANIS, FAIL);
}
if (uiCarrionSwarmTimer < diff)
@@ -197,7 +193,7 @@ public:
switch (uiOutroStep)
{
case 1:
- Talk(SAY_ESCAPE_SPEECH_1);
+ Talk(SAY_OUTRO);
me->GetMotionMaster()->MoveTargetedHome();
++uiOutroStep;
uiOutroTimer = 8000;
@@ -212,7 +208,7 @@ public:
case 3:
Talk(SAY_OUTRO);
++uiOutroStep;
- uiOutroTimer = 16000;
+ //uiOutroTimer = 16000;
break;
case 4:
me->HandleEmoteCommand(33);
@@ -232,7 +228,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
- instance->SetData(DATA_MAL_GANIS_EVENT, DONE);
+ instance->SetBossState(DATA_MAL_GANIS, DONE);
DoCastAOE(SPELL_MAL_GANIS_KILL_CREDIT);
// give achievement credit and LFG rewards to players. criteria use spell 58630 which doesn't exist, but it was created in spell_dbc
DoCastAOE(SPELL_KILL_CREDIT);
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
index c961bf9b2c6..143f901ec0b 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
@@ -15,14 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* Script Data Start
-SDName: Boss meathook
-SDAuthor: Tartalo
-SD%Complete: 100
-SDComment: It may need timer adjustment
-SDCategory:
-Script Data End */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "culling_of_stratholme.h"
@@ -30,9 +22,7 @@ Script Data End */
enum Spells
{
SPELL_CONSTRICTING_CHAINS = 52696, //Encases the targets in chains, dealing 1800 Physical damage every 1 sec. and stunning the target for 5 sec.
- H_SPELL_CONSTRICTING_CHAINS = 58823,
SPELL_DISEASE_EXPULSION = 52666, //Meathook belches out a cloud of disease, dealing 1710 to 1890 Nature damage and interrupting the spell casting of nearby enemy targets for 4 sec.
- H_SPELL_DISEASE_EXPULSION = 58824,
SPELL_FRENZY = 58841 //Increases the caster's Physical damage by 10% for 30 sec.
};
@@ -44,96 +34,72 @@ enum Yells
SAY_DEATH = 3
};
-class boss_meathook : public CreatureScript
+enum Events
{
-public:
- boss_meathook() : CreatureScript("boss_meathook") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_meathookAI>(creature);
- }
-
- struct boss_meathookAI : public ScriptedAI
- {
- boss_meathookAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- Talk(SAY_SPAWN);
- }
-
- void Initialize()
- {
- uiChainTimer = urand(12000, 17000); //seen on video 13, 17, 15, 12, 16
- uiDiseaseTimer = urand(2000, 4000); //approx 3s
- uiFrenzyTimer = urand(21000, 26000); //made it up
- }
-
- uint32 uiChainTimer;
- uint32 uiDiseaseTimer;
- uint32 uiFrenzyTimer;
-
- InstanceScript* instance;
-
- void Reset() override
- {
- Initialize();
-
- instance->SetData(DATA_MEATHOOK_EVENT, NOT_STARTED);
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
+ EVENT_CHAIN = 1,
+ EVENT_DISEASE,
+ EVENT_FRENZY
+};
- instance->SetData(DATA_MEATHOOK_EVENT, IN_PROGRESS);
- }
+class boss_meathook : public CreatureScript
+{
+ public:
+ boss_meathook() : CreatureScript("boss_meathook") { }
- void UpdateAI(uint32 diff) override
+ struct boss_meathookAI : public BossAI
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (uiDiseaseTimer <= diff)
+ boss_meathookAI(Creature* creature) : BossAI(creature, DATA_MEATHOOK)
{
- DoCastAOE(SPELL_DISEASE_EXPULSION);
- uiDiseaseTimer = urand(1500, 4000);
- } else uiDiseaseTimer -= diff;
+ Talk(SAY_SPAWN);
+ }
- if (uiFrenzyTimer <= diff)
+ void EnterCombat(Unit* /*who*/) override
{
- DoCast(me, SPELL_FRENZY);
- uiFrenzyTimer = urand(21000, 26000);
- } else uiFrenzyTimer -= diff;
-
- if (uiChainTimer <= diff)
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_CHAIN, urand(12000, 17000));
+ events.ScheduleEvent(EVENT_DISEASE, urand(2000, 4000));
+ events.ScheduleEvent(EVENT_FRENZY, urand(21000, 26000));
+ }
+
+ void ExecuteEvent(uint32 eventId) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_CONSTRICTING_CHAINS); //anyone but the tank
- uiChainTimer = urand(2000, 4000);
- } else uiChainTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
+ switch (eventId)
+ {
+ case EVENT_CHAIN:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CONSTRICTING_CHAINS);
+ events.ScheduleEvent(EVENT_CHAIN, urand(2000, 4000));
+ case EVENT_DISEASE:
+ DoCastAOE(SPELL_DISEASE_EXPULSION);
+ events.ScheduleEvent(EVENT_DISEASE, urand(1500, 4000));
+ break;
+ case EVENT_FRENZY:
+ DoCast(me, SPELL_FRENZY);
+ events.ScheduleEvent(EVENT_FRENZY, urand(21000, 26000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
- instance->SetData(DATA_MEATHOOK_EVENT, DONE);
- }
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+ };
- void KilledUnit(Unit* victim) override
+ CreatureAI* GetAI(Creature* creature) const override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ return GetInstanceAI<boss_meathookAI>(creature);
}
- };
-
};
void AddSC_boss_meathook()
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
index 1c35a38a5e3..6925badf272 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
@@ -89,14 +89,14 @@ public:
{
Initialize();
- instance->SetData(DATA_SALRAMM_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_SALRAMM, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_SALRAMM_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_SALRAMM, IN_PROGRESS);
}
void UpdateAI(uint32 diff) override
@@ -145,7 +145,7 @@ public:
{
Talk(SAY_DEATH);
- instance->SetData(DATA_SALRAMM_EVENT, DONE);
+ instance->SetBossState(DATA_SALRAMM, DONE);
}
void KilledUnit(Unit* victim) override
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
index b8a9b295161..3c80be2734a 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
@@ -103,7 +103,7 @@ enum Says
//Drakonian
SAY_PHASE302 = 0,
- SAY_PHASE305 = 1,
+ SAY_PHASE305 = 1
};
enum NPCs
@@ -111,7 +111,6 @@ enum NPCs
NPC_INFINITE_ADVERSARY = 27742,
NPC_INFINITE_HUNTER = 27743,
NPC_INFINITE_AGENT = 27744,
- NPC_TIME_RIFT = 28409,
NPC_ZOMBIE = 27737,
NPC_GHOUL = 28249,
NPC_NECROMANCER = 28200,
@@ -128,7 +127,7 @@ enum NPCs
NPC_CITY_MAN = 28167,
NPC_CITY_MAN2 = 28169,
NPC_CITY_MAN3 = 31126,
- NPC_CITY_MAN4 = 31127,
+ NPC_CITY_MAN4 = 31127
};
enum Spells
@@ -138,7 +137,7 @@ enum Spells
SPELL_EXORCISM_N = 52445,
SPELL_EXORCISM_H = 58822,
SPELL_HOLY_LIGHT = 52444,
- SPELL_ARCANE_DISRUPTION = 49590,
+ SPELL_ARCANE_DISRUPTION = 49590
};
enum GossipMenuArthas
@@ -392,6 +391,7 @@ public:
uint32 gossipStep;
uint32 bossEvent;
uint32 wave;
+ uint32 WavesCounter;
uint64 utherGUID;
uint64 jainaGUID;
@@ -411,17 +411,19 @@ public:
{
Initialize();
- instance->SetData(DATA_ARTHAS_EVENT, NOT_STARTED);
- switch (instance->GetData(DATA_ARTHAS_EVENT))
- {
- case NOT_STARTED:
- bStepping = true;
- step = 0;
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- bossEvent = DATA_MEATHOOK_EVENT;
- gossipStep = 0;
- break;
- }
+ instance->SetBossState(DATA_ARTHAS, NOT_STARTED);
+
+ bStepping = true;
+ step = 0;
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ bossEvent = DATA_MEATHOOK;
+ gossipStep = 0;
+ }
+
+ void AttackStart(Unit* who)
+ {
+ if (who && !who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC))
+ npc_escortAI::AttackStart(who);
}
void EnterCombat(Unit* /*who*/) override
@@ -431,7 +433,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
- instance->SetData(DATA_ARTHAS_EVENT, FAIL);
+ instance->SetBossState(DATA_ARTHAS, FAIL);
}
void SpawnTimeRift(uint32 timeRiftID, uint64* guidVector)
@@ -488,16 +490,15 @@ public:
case 11:
case 22:
case 23:
- case 26:
case 55:
case 56:
SetHoldState(true);
bStepping = true;
break;
case 7:
- if (Unit* cityman0 = me->SummonCreature(NPC_CITY_MAN, 2091.977f, 1275.021f, 140.757f, 0.558f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000))
+ if (Unit* cityman0 = me->FindNearestCreature(NPC_CITY_MAN, 160.0f))
citymenGUID[0] = cityman0->GetGUID();
- if (Unit* cityman1 = me->SummonCreature(NPC_CITY_MAN2, 2093.514f, 1275.842f, 140.408f, 3.801f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000))
+ if (Unit* cityman1 = me->FindNearestCreature(NPC_CITY_MAN2, 160.0f))
citymenGUID[1] = cityman1->GetGUID();
break;
case 8:
@@ -534,10 +535,12 @@ public:
case 21:
Talk(SAY_PHASE301);
break;
- case 25:
+ case 26:
SetRun(false);
SpawnTimeRift(0, &infiniteDraconianGUID[0]);
Talk(SAY_PHASE307);
+ SetHoldState(true);
+ bStepping = true;
break;
case 29:
SetRun(false);
@@ -565,8 +568,8 @@ public:
Talk(SAY_PHASE403);
break;
case 36:
- if (GameObject* pGate = instance->instance->GetGameObject(instance->GetData64(DATA_SHKAF_GATE)))
- pGate->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_SHKAF_GATE)))
+ gate->SetGoState(GO_STATE_ACTIVE);
break;
case 45:
SetRun(true);
@@ -575,18 +578,18 @@ public:
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
SetHoldState(true);
break;
- case 47:
+ case 48:
SetRun(false);
Talk(SAY_PHASE405);
break;
- case 48:
+ case 49:
SetRun(true);
Talk(SAY_PHASE406);
break;
- case 53:
+ case 50:
Talk(SAY_PHASE407);
break;
- case 54:
+ case 51:
gossipStep = 5;
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
SetHoldState(true);
@@ -598,8 +601,6 @@ public:
{
npc_escortAI::UpdateAI(diff);
- DoMeleeAttackIfReady();
-
if (bStepping)
{
if (phaseTimer <= diff)
@@ -765,6 +766,9 @@ public:
stalkerGUID = pStalker->GetGUID();
me->SetTarget(stalkerGUID);
}
+
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, 0);
+
JumpToNextStep(1000);
break;
case 25:
@@ -892,14 +896,15 @@ public:
}
Talk(SAY_PHASE209);
- bossEvent = DATA_MEATHOOK_EVENT;
- instance->SetData(DATA_ARTHAS_EVENT, IN_PROGRESS);
+ bossEvent = DATA_MEATHOOK;
+ instance->SetBossState(DATA_ARTHAS, IN_PROGRESS);
me->SetReactState(REACT_DEFENSIVE);
SetDespawnAtFar(false);
JumpToNextStep(5000);
break;
- case 41: //Summon wave group
+ // Summon wave groups - start the Infinite Corruptor timer
+ case 41:
case 43:
case 45:
case 47:
@@ -907,10 +912,15 @@ public:
case 53:
case 55:
case 57:
- if (instance->GetData(bossEvent) != DONE)
+ if (!wave && IsHeroic() && instance->GetData(DATA_INFINITE_COUNTER) == NOT_STARTED)
+ instance->SetData(DATA_INFINITE_COUNTER, IN_PROGRESS);
+
+ if (instance->GetBossState(bossEvent) != DONE)
{
SpawnWaveGroup(wave, waveGUID);
wave++;
+ WavesCounter++;
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, WavesCounter);
}
JumpToNextStep(500);
break;
@@ -922,7 +932,7 @@ public:
case 54:
case 56:
case 58:
- if (instance->GetData(bossEvent) != DONE)
+ if (instance->GetBossState(bossEvent) != DONE)
{
uint32 mobCounter = 0;
uint32 deadCounter = 0;
@@ -946,12 +956,14 @@ public:
break;
case 49: //Summon Boss
case 59:
- if (instance->GetData(bossEvent) != DONE)
+ if (instance->GetBossState(bossEvent) != DONE)
{
+ WavesCounter++;
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, WavesCounter);
uint32 uiBossID = 0;
- if (bossEvent == DATA_MEATHOOK_EVENT)
+ if (bossEvent == DATA_MEATHOOK)
uiBossID = NPC_MEATHOOK;
- else if (bossEvent == DATA_SALRAMM_EVENT)
+ else if (bossEvent == DATA_SALRAMM)
uiBossID = NPC_SALRAMM;
if (Unit* pBoss = me->SummonCreature(uiBossID, 2232.19f, 1331.933f, 126.662f, 3.15f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000))
@@ -965,19 +977,19 @@ public:
break;
case 50: //Wait Boss death
case 60:
- if (instance->GetData(bossEvent) == DONE)
+ if (instance->GetBossState(bossEvent) == DONE)
{
JumpToNextStep(1000);
- if (bossEvent == DATA_MEATHOOK_EVENT)
- bossEvent = DATA_SALRAMM_EVENT;
- else if (bossEvent == DATA_SALRAMM_EVENT)
+ if (bossEvent == DATA_MEATHOOK)
+ bossEvent = DATA_SALRAMM;
+ else if (bossEvent == DATA_SALRAMM)
{
SetHoldState(false);
bStepping = false;
- bossEvent = DATA_EPOCH_EVENT;
+ bossEvent = DATA_EPOCH;
}
}
- else if (instance->GetData(bossEvent) == FAIL)
+ else if (instance->GetBossState(bossEvent) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1074,9 +1086,12 @@ public:
phaseTimer = 1000;
else
{
- if (step == 72) Talk(SAY_PHASE308);
- if (step == 74) Talk(SAY_PHASE308);
- if (step == 76) Talk(SAY_PHASE310);
+ if (step == 72)
+ Talk(SAY_PHASE308);
+ if (step == 74)
+ Talk(SAY_PHASE308);
+ if (step == 76)
+ Talk(SAY_PHASE310);
SetHoldState(false);
bStepping = false;
SetRun(true);
@@ -1097,7 +1112,7 @@ public:
JumpToNextStep(1000);
break;
case 80:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
{
SpawnTimeRift(17, &epochGUID);
if (Creature* epoch = ObjectAccessor::GetCreature(*me, epochGUID))
@@ -1107,12 +1122,12 @@ public:
JumpToNextStep(18000);
break;
case 81:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
Talk(SAY_PHASE315);
JumpToNextStep(6000);
break;
case 82:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
{
if (Creature* epoch = ObjectAccessor::GetCreature(*me, epochGUID))
{
@@ -1126,15 +1141,15 @@ public:
JumpToNextStep(1000);
break;
case 83:
- if (instance->GetData(DATA_EPOCH_EVENT) == DONE)
+ if (instance->GetBossState(DATA_EPOCH) == DONE)
{
gossipStep = 3;
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
bStepping = false;
- bossEvent = DATA_MAL_GANIS_EVENT;
+ bossEvent = DATA_MAL_GANIS;
JumpToNextStep(15000);
}
- else if (instance->GetData(DATA_EPOCH_EVENT) == FAIL)
+ else if (instance->GetBossState(DATA_EPOCH) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1153,8 +1168,8 @@ public:
malganisGUID = malganis->GetGUID();
malganis->SetReactState(REACT_PASSIVE);
}
- if (GameObject* pGate = instance->instance->GetGameObject(instance->GetData64(DATA_MAL_GANIS_GATE_1)))
- pGate->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MAL_GANIS_GATE_1)))
+ gate->SetGoState(GO_STATE_ACTIVE);
SetHoldState(false);
bStepping = false;
JumpToNextStep(0);
@@ -1174,12 +1189,12 @@ public:
JumpToNextStep(1000);
break;
case 88:
- if (instance->GetData(DATA_MAL_GANIS_EVENT) == DONE)
+ if (instance->GetBossState(DATA_MAL_GANIS) == DONE)
{
SetHoldState(false);
JumpToNextStep(1000);
}
- else if (instance->GetData(DATA_MAL_GANIS_EVENT) == FAIL)
+ else if (instance->GetBossState(DATA_MAL_GANIS) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1192,7 +1207,7 @@ public:
JumpToNextStep(7000);
break;
case 90:
- instance->SetData(DATA_ARTHAS_EVENT, DONE); //Rewards: Achiev & Chest ;D
+ instance->SetBossState(DATA_ARTHAS, DONE); //Rewards: Achiev & Chest ;D
me->SetTarget(instance->GetData64(DATA_MAL_GANIS_GATE_2)); //Look behind
Talk(SAY_PHASE504);
bStepping = false;
@@ -1214,6 +1229,8 @@ public:
if (HealthBelowPct(40))
DoCast(me, SPELL_HOLY_LIGHT);
+
+ DoMeleeAttackIfReady();
}
};
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
index e7d1033e55f..192654c87f1 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
@@ -19,19 +19,10 @@
#define DEF_CULLING_OF_STRATHOLME_H
#define DataHeader "CS"
+#define CoSScriptName "instance_culling_of_stratholme"
+uint32 const EncounterCount = 5;
-enum Data
-{
- DATA_MEATHOOK_EVENT,
- DATA_SALRAMM_EVENT,
- DATA_EPOCH_EVENT,
- DATA_MAL_GANIS_EVENT,
- DATA_INFINITE_EVENT,
- DATA_ARTHAS_EVENT,
- DATA_CRATE_COUNT,
-};
-
-enum Data64
+enum DataTypes
{
DATA_ARTHAS,
DATA_MEATHOOK,
@@ -39,28 +30,35 @@ enum Data64
DATA_EPOCH,
DATA_MAL_GANIS,
DATA_INFINITE,
+ DATA_CRATE_COUNT,
DATA_SHKAF_GATE,
DATA_MAL_GANIS_GATE_1,
DATA_MAL_GANIS_GATE_2,
DATA_EXIT_GATE,
- DATA_MAL_GANIS_CHEST
+ DATA_MAL_GANIS_CHEST,
+ DATA_INFINITE_COUNTER
};
-enum Creatures
+enum CreatureIds
{
- NPC_MEATHOOK = 26529,
- NPC_SALRAMM = 26530,
- NPC_EPOCH = 26532,
- NPC_MAL_GANIS = 26533,
- NPC_INFINITE = 32273,
- NPC_ARTHAS = 26499,
- NPC_JAINA = 26497,
- NPC_UTHER = 26528,
- NPC_CHROMIE_2 = 27915,
- NPC_GENERIC_BUNNY = 28960,
+ NPC_MEATHOOK = 26529,
+ NPC_SALRAMM = 26530,
+ NPC_EPOCH = 26532,
+ NPC_MAL_GANIS = 26533,
+ NPC_INFINITE = 32273,
+ NPC_ARTHAS = 26499,
+ NPC_JAINA = 26497,
+ NPC_UTHER = 26528,
+ NPC_CHROMIE = 26527,
+ NPC_CHROMIE_2 = 27915,
+ NPC_CHROMIE_3 = 30997,
+ NPC_GENERIC_BUNNY = 28960,
+
+ NPC_TIME_RIFT = 28409,
+ NPC_GUARDIAN_OF_TIME = 32281
};
-enum GameObjects
+enum GameObjectIds
{
GO_SHKAF_GATE = 188686,
GO_MALGANIS_GATE_1 = 187711,
@@ -69,7 +67,7 @@ enum GameObjects
GO_MALGANIS_CHEST_N = 190663,
GO_MALGANIS_CHEST_H = 193597,
GO_SUSPICIOUS_CRATE = 190094,
- GO_PLAGUED_CRATE = 190095,
+ GO_PLAGUED_CRATE = 190095
};
enum WorldStatesCoT
@@ -78,12 +76,28 @@ enum WorldStatesCoT
WORLDSTATE_CRATES_REVEALED = 3480,
WORLDSTATE_WAVE_COUNT = 3504,
WORLDSTATE_TIME_GUARDIAN = 3931,
- WORLDSTATE_TIME_GUARDIAN_SHOW = 3932,
+ WORLDSTATE_TIME_GUARDIAN_SHOW = 3932
};
enum CrateSpells
{
- SPELL_CRATES_CREDIT = 58109,
+ SPELL_CRATES_CREDIT = 58109
+};
+
+enum Texts
+{
+ SAY_CRATES_COMPLETED = 0,
+ // Chromie
+ SAY_INFINITE_START = 0, // On Infinite Corruptor event start
+ SAY_INFINITE = 1, // On Infinite Corruptor event at 5 minutes
+ SAY_INFINITE_FAIL = 2, // On Infinite Corruptor event fail
+ // Infinite Corruptor
+ SAY_FAIL_EVENT = 2 // On Infinite Corruptor event fail
+};
+
+enum InstanceEvents
+{
+ EVENT_INFINITE_TIMER = 1
};
#endif
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
index 7af2b3f63aa..b3e8d88bc2a 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
@@ -23,8 +23,6 @@
#include "TemporarySummon.h"
#include "SpellInfo.h"
-#define MAX_ENCOUNTER 5
-
/* Culling of Stratholme encounters:
0 - Meathook
1 - Salramm the Fleshcrafter
@@ -33,51 +31,51 @@
4 - Infinite Corruptor (Heroic only)
*/
-enum Texts
+Position const ChromieSummonPos[] =
{
- SAY_CRATES_COMPLETED = 0,
+ { 1813.298f, 1283.578f, 142.3258f, 3.878161f },
+ { 2273.725f, 1483.684f, 128.7205f, 6.057528f }
};
-Position const ChromieSummonPos = {1813.298f, 1283.578f, 142.3258f, 3.878161f};
+Position const InfiniteCorruptorPos = { 2335.47f, 1262.04f, 132.921f, 1.42079f };
+Position const TimeRiftPos = { 2334.626f, 1280.45f, 133.0066f, 1.727876f };
+Position const GuardianOfTimePos = { 2321.489f, 1268.383f, 132.8507f, 0.418879f };
+
+DoorData const doorData[] =
+{
+ { GO_MALGANIS_GATE_2, DATA_MAL_GANIS, DOOR_TYPE_ROOM, BOUNDARY_NONE },
+ { GO_EXIT_GATE, DATA_MAL_GANIS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
+};
class instance_culling_of_stratholme : public InstanceMapScript
{
public:
- instance_culling_of_stratholme() : InstanceMapScript("instance_culling_of_stratholme", 595) { }
-
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_culling_of_stratholme_InstanceMapScript(map);
- }
+ instance_culling_of_stratholme() : InstanceMapScript(CoSScriptName, 595) { }
struct instance_culling_of_stratholme_InstanceMapScript : public InstanceScript
{
instance_culling_of_stratholme_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
- _arthasGUID = 0;
- _meathookGUID = 0;
- _salrammGUID = 0;
- _epochGUID = 0;
- _malGanisGUID = 0;
- _infiniteGUID = 0;
- _shkafGateGUID = 0;
+ SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
+
+ _chromieGUID = 0;
+ _arthasGUID = 0;
+ _meathookGUID = 0;
+ _salrammGUID = 0;
+ _epochGUID = 0;
+ _malGanisGUID = 0;
+ _infiniteGUID = 0;
+ _shkafGateGUID = 0;
_malGanisGate1GUID = 0;
_malGanisGate2GUID = 0;
- _exitGateGUID = 0;
+ _exitGateGUID = 0;
_malGanisChestGUID = 0;
- _genericBunnyGUID = 0;
- memset(&_encounterState[0], 0, sizeof(uint32) * MAX_ENCOUNTER);
- _crateCount = 0;
- }
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (_encounterState[i] == IN_PROGRESS)
- return true;
-
- return false;
+ _genericBunnyGUID = 0;
+ _crateCount = 0;
+ _eventTimer = 0;
}
void FillInitialWorldStates(WorldPacket& data) override
@@ -93,6 +91,9 @@ class instance_culling_of_stratholme : public InstanceMapScript
{
switch (creature->GetEntry())
{
+ case NPC_CHROMIE:
+ _chromieGUID = creature->GetGUID();
+ break;
case NPC_ARTHAS:
_arthasGUID = creature->GetGUID();
break;
@@ -110,10 +111,13 @@ class instance_culling_of_stratholme : public InstanceMapScript
break;
case NPC_INFINITE:
_infiniteGUID = creature->GetGUID();
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 1);
break;
case NPC_GENERIC_BUNNY:
_genericBunnyGUID = creature->GetGUID();
break;
+ default:
+ break;
}
}
@@ -129,55 +133,38 @@ class instance_culling_of_stratholme : public InstanceMapScript
break;
case GO_MALGANIS_GATE_2:
_malGanisGate2GUID = go->GetGUID();
+ AddDoor(go, true);
break;
case GO_EXIT_GATE:
_exitGateGUID = go->GetGUID();
- if (_encounterState[3] == DONE)
- HandleGameObject(_exitGateGUID, true);
+ AddDoor(go, true);
break;
case GO_MALGANIS_CHEST_N:
case GO_MALGANIS_CHEST_H:
_malGanisChestGUID = go->GetGUID();
- if (_encounterState[3] == DONE)
- go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
+ break;
+ default:
break;
}
}
- void SetData(uint32 type, uint32 data) override
+ void OnGameObjectRemove(GameObject* go) override
{
- switch (type)
+ switch (go->GetEntry())
{
- case DATA_MEATHOOK_EVENT:
- _encounterState[0] = data;
- break;
- case DATA_SALRAMM_EVENT:
- _encounterState[1] = data;
+ case GO_MALGANIS_GATE_2:
+ case GO_EXIT_GATE:
+ AddDoor(go, false);
break;
- case DATA_EPOCH_EVENT:
- _encounterState[2] = data;
+ default:
break;
- case DATA_MAL_GANIS_EVENT:
- _encounterState[3] = data;
+ }
+ }
- switch (_encounterState[3])
- {
- case NOT_STARTED:
- HandleGameObject(_malGanisGate2GUID, true);
- break;
- case IN_PROGRESS:
- HandleGameObject(_malGanisGate2GUID, false);
- break;
- case DONE:
- HandleGameObject(_exitGateGUID, true);
- if (GameObject* go = instance->GetGameObject(_malGanisChestGUID))
- go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
- break;
- }
- break;
- case DATA_INFINITE_EVENT:
- _encounterState[4] = data;
- break;
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
case DATA_CRATE_COUNT:
_crateCount = data;
if (_crateCount == 5)
@@ -186,34 +173,70 @@ class instance_culling_of_stratholme : public InstanceMapScript
bunny->CastSpell(bunny, SPELL_CRATES_CREDIT, true);
// Summon Chromie and global whisper
- if (Creature* chromie = instance->SummonCreature(NPC_CHROMIE_2, ChromieSummonPos))
+ if (Creature* chromie = instance->SummonCreature(NPC_CHROMIE_2, ChromieSummonPos[0]))
if (!instance->GetPlayers().isEmpty())
chromie->AI()->TalkToMap(SAY_CRATES_COMPLETED);
}
DoUpdateWorldState(WORLDSTATE_CRATES_REVEALED, _crateCount);
break;
+ case DATA_INFINITE_COUNTER:
+ _infiniteCouterState = data;
+ if (data == IN_PROGRESS)
+ {
+ if (!_infiniteGUID)
+ {
+ _eventTimer = 25;
+ instance->SummonCreature(NPC_INFINITE, InfiniteCorruptorPos);
+ instance->SummonCreature(NPC_TIME_RIFT, TimeRiftPos);
+ instance->SummonCreature(NPC_GUARDIAN_OF_TIME, GuardianOfTimePos);
+ events.ScheduleEvent(EVENT_INFINITE_TIMER, 1);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DATA_INFINITE:
+ if (state == DONE)
+ {
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 0);
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN, 0);
+ }
+ break;
+ case DATA_MAL_GANIS:
+ if (state == DONE)
+ {
+ if (GameObject* go = instance->GetGameObject(_malGanisChestGUID))
+ go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
+ instance->SummonCreature(NPC_CHROMIE_3, ChromieSummonPos[1]);
+ }
+ break;
+ default:
+ break;
}
- if (data == DONE)
- SaveToDB();
+ return true;
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
- case DATA_MEATHOOK_EVENT:
- return _encounterState[0];
- case DATA_SALRAMM_EVENT:
- return _encounterState[1];
- case DATA_EPOCH_EVENT:
- return _encounterState[2];
- case DATA_MAL_GANIS_EVENT:
- return _encounterState[3];
- case DATA_INFINITE_EVENT:
- return _encounterState[4];
case DATA_CRATE_COUNT:
return _crateCount;
+ case DATA_INFINITE_COUNTER:
+ return _infiniteCouterState;
+ default:
+ break;
}
return 0;
}
@@ -244,58 +267,70 @@ class instance_culling_of_stratholme : public InstanceMapScript
return _exitGateGUID;
case DATA_MAL_GANIS_CHEST:
return _malGanisChestGUID;
+ default:
+ break;
}
return 0;
}
- std::string GetSaveData() override
+ void Update(uint32 diff) override
{
- OUT_SAVE_INST_DATA;
+ events.Update(diff);
- std::ostringstream saveStream;
- saveStream << "C S " << _encounterState[0] << ' ' << _encounterState[1] << ' '
- << _encounterState[2] << ' ' << _encounterState[3] << ' ' << _encounterState[4];
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return saveStream.str();
- }
-
- void Load(const char* in) override
- {
- if (!in)
+ while (uint32 eventId = events.ExecuteEvent())
{
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
-
- OUT_LOAD_INST_DATA(in);
-
- char dataHead1, dataHead2;
- uint16 data0, data1, data2, data3, data4;
-
- std::istringstream loadStream(in);
- loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4;
-
- if (dataHead1 == 'C' && dataHead2 == 'S')
- {
- _encounterState[0] = data0;
- _encounterState[1] = data1;
- _encounterState[2] = data2;
- _encounterState[3] = data3;
- _encounterState[4] = data4;
-
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (_encounterState[i] == IN_PROGRESS)
- _encounterState[i] = NOT_STARTED;
-
+ switch (eventId)
+ {
+ case EVENT_INFINITE_TIMER:
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN, _eventTimer);
+
+ switch (_eventTimer)
+ {
+ case 25:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE_START);
+ break;
+ case 5:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE);
+ break;
+ case 0:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE_FAIL);
+
+ if (Creature* infinite = instance->GetCreature(_infiniteGUID))
+ {
+ if (Creature* guardian = infinite->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ infinite->Kill(guardian);
+
+ if (Creature* rift = infinite->FindNearestCreature(NPC_TIME_RIFT, 100.0f))
+ {
+ infinite->GetMotionMaster()->MovePoint(0, rift->GetPositionX(), rift->GetPositionY(), rift->GetPositionZ());
+ rift->DespawnOrUnsummon(3000);
+ }
+
+ infinite->DespawnOrUnsummon(3000);
+ infinite->AI()->Talk(SAY_FAIL_EVENT);
+ }
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 0);
+ return;
+ default:
+ break;
+ }
+ events.ScheduleEvent(EVENT_INFINITE_TIMER, 60000);
+ --_eventTimer;
+ break;
+ default:
+ break;
+ }
}
- else
- OUT_LOAD_INST_DATA_FAIL;
-
- OUT_LOAD_INST_DATA_COMPLETE;
}
private:
+ uint64 _chromieGUID;
uint64 _arthasGUID;
uint64 _meathookGUID;
uint64 _salrammGUID;
@@ -308,9 +343,18 @@ class instance_culling_of_stratholme : public InstanceMapScript
uint64 _exitGateGUID;
uint64 _malGanisChestGUID;
uint64 _genericBunnyGUID;
- uint32 _encounterState[MAX_ENCOUNTER];
+
uint32 _crateCount;
+ uint32 _eventTimer;
+ uint32 _infiniteCouterState;
+
+ EventMap events;
};
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_culling_of_stratholme_InstanceMapScript(map);
+ }
};
void AddSC_instance_culling_of_stratholme()
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index ff507f32bae..3670e225fd7 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -487,6 +487,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/Gundrak/boss_eck.cpp b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
index 0783a79b381..9f8cc818958 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
@@ -28,146 +28,92 @@ enum Spells
SPELL_ECK_SPRING_2 = 55837 //Eck leaps at a distant target.
};
-static Position EckSpawnPoint = { 1643.877930f, 936.278015f, 107.204948f, 0.668432f };
+enum Events
+{
+ EVENT_BITE = 1,
+ EVENT_SPIT,
+ EVENT_SPRING,
+ EVENT_BERSERK
+};
class boss_eck : public CreatureScript
{
public:
boss_eck() : CreatureScript("boss_eck") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_eckAI>(creature);
- }
-
- struct boss_eckAI : public ScriptedAI
+ struct boss_eckAI : public BossAI
{
- boss_eckAI(Creature* creature) : ScriptedAI(creature)
+ boss_eckAI(Creature* creature) : BossAI(creature, DATA_ECK_THE_FEROCIOUS_EVENT)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
{
- uiBerserkTimer = urand(60 * IN_MILLISECONDS, 90 * IN_MILLISECONDS); //60-90 secs according to wowwiki
- uiBiteTimer = 5 * IN_MILLISECONDS;
- uiSpitTimer = 10 * IN_MILLISECONDS;
- uiSpringTimer = 8 * IN_MILLISECONDS;
-
- bBerserk = false;
+ Berserk = false;
}
- uint32 uiBerserkTimer;
- uint32 uiBiteTimer;
- uint32 uiSpitTimer;
- uint32 uiSpringTimer;
-
- bool bBerserk;
-
- InstanceScript* instance;
-
void Reset() override
{
+ _Reset();
Initialize();
-
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, IN_PROGRESS);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_BITE, 5 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPIT, 10 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPRING, 8 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_BERSERK, urand(60 * IN_MILLISECONDS, 90 * IN_MILLISECONDS)); //60-90 secs according to wowwiki
}
- void UpdateAI(uint32 diff) override
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (uiBiteTimer <= diff)
- {
- DoCastVictim(SPELL_ECK_BITE);
- uiBiteTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS);
- } else uiBiteTimer -= diff;
-
- if (uiSpitTimer <= diff)
+ if (me->HealthBelowPctDamaged(20, damage) && !Berserk)
{
- DoCastVictim(SPELL_ECK_SPIT);
- uiSpitTimer = urand(6*IN_MILLISECONDS, 14*IN_MILLISECONDS);
- } else uiSpitTimer -= diff;
-
- if (uiSpringTimer <= diff)
- {
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- {
- DoCast(target, RAND(SPELL_ECK_SPRING_1, SPELL_ECK_SPRING_2));
- uiSpringTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS);
- }
- } else uiSpringTimer -= diff;
+ events.RescheduleEvent(EVENT_BERSERK, 1000);
+ Berserk = true;
+ }
+ }
- //Berserk on timer or 20% of health
- if (!bBerserk)
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
- if (uiBerserkTimer <= diff)
- {
+ case EVENT_BITE:
+ DoCastVictim(SPELL_ECK_BITE);
+ events.ScheduleEvent(EVENT_BITE, urand(8 * IN_MILLISECONDS, 12 * IN_MILLISECONDS));
+ break;
+ case EVENT_SPIT:
+ DoCastVictim(SPELL_ECK_SPIT);
+ events.ScheduleEvent(EVENT_SPIT, urand(6 * IN_MILLISECONDS, 14 * IN_MILLISECONDS));
+ break;
+ case EVENT_SPRING:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 35.0f, true))
+ DoCast(target, RAND(SPELL_ECK_SPRING_1, SPELL_ECK_SPRING_2));
+ events.ScheduleEvent(EVENT_SPRING, urand(5 * IN_MILLISECONDS, 10 * IN_MILLISECONDS));
+ break;
+ case EVENT_BERSERK:
DoCast(me, SPELL_ECK_BERSERK);
- bBerserk = true;
- }
- else
- {
- uiBerserkTimer -= diff;
- if (HealthBelowPct(20))
- {
- DoCast(me, SPELL_ECK_BERSERK);
- bBerserk = true;
- }
- }
+ Berserk = true;
+ break;
+ default:
+ break;
}
-
- DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, DONE);
- }
+ private:
+ bool Berserk;
};
-};
-
-class npc_ruins_dweller : public CreatureScript
-{
-public:
- npc_ruins_dweller() : CreatureScript("npc_ruins_dweller") { }
-
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<npc_ruins_dwellerAI>(creature);
+ return GetInstanceAI<boss_eckAI>(creature);
}
-
- struct npc_ruins_dwellerAI : public ScriptedAI
- {
- npc_ruins_dwellerAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
-
- InstanceScript* instance;
-
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData64(DATA_RUIN_DWELLER_DIED, me->GetGUID());
- if (instance->GetData(DATA_ALIVE_RUIN_DWELLERS) == 0)
- me->SummonCreature(CREATURE_ECK, EckSpawnPoint, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300*IN_MILLISECONDS);
- }
- };
-
};
void AddSC_boss_eck()
{
new boss_eck();
- new npc_ruins_dweller();
}
diff --git a/src/server/scripts/Northrend/Gundrak/gundrak.h b/src/server/scripts/Northrend/Gundrak/gundrak.h
index 8f269705a45..fffeca82f39 100644
--- a/src/server/scripts/Northrend/Gundrak/gundrak.h
+++ b/src/server/scripts/Northrend/Gundrak/gundrak.h
@@ -26,8 +26,7 @@ enum Data
DATA_MOORABI_EVENT,
DATA_DRAKKARI_COLOSSUS_EVENT,
DATA_GAL_DARAH_EVENT,
- DATA_ECK_THE_FEROCIOUS_EVENT,
- DATA_ALIVE_RUIN_DWELLERS
+ DATA_ECK_THE_FEROCIOUS_EVENT
};
enum Data64
@@ -39,8 +38,7 @@ enum Data64
DATA_MOORABI_STATUE,
DATA_DRAKKARI_COLOSSUS_STATUE,
DATA_DRAKKARI_COLOSSUS,
- DATA_RUIN_DWELLER_DIED,
- DATA_STATUE_ACTIVATE,
+ DATA_STATUE_ACTIVATE
};
enum mainCreatures
diff --git a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
index e5efdad27f3..388d43e8dca 100644
--- a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
+++ b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
@@ -31,6 +31,8 @@
4 - Eck the Ferocious
*/
+Position const EckSpawnPoint = { 1643.877930f, 936.278015f, 107.204948f, 0.668432f };
+
class instance_gundrak : public InstanceMapScript
{
public:
@@ -134,7 +136,7 @@ public:
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
}
- bool IsEncounterInProgress() const override
+ bool IsEncounterInProgress() const override
{
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS)
@@ -274,6 +276,17 @@ public:
}
}
+ void OnUnitDeath(Unit* unit) override
+ {
+ if (unit->GetEntry() == CREATURE_RUIN_DWELLER)
+ {
+ DwellerGUIDs.erase(unit->GetGUID());
+
+ if (DwellerGUIDs.empty())
+ unit->SummonCreature(CREATURE_ECK, EckSpawnPoint, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300 * IN_MILLISECONDS);
+ }
+ }
+
void SetData(uint32 type, uint32 data) override
{
switch (type)
@@ -329,9 +342,7 @@ public:
void SetData64(uint32 type, uint64 data) override
{
- if (type == DATA_RUIN_DWELLER_DIED)
- DwellerGUIDs.erase(data);
- else if (type == DATA_STATUE_ACTIVATE)
+ if (type == DATA_STATUE_ACTIVATE)
{
toActivate = data;
timer = 3500;
@@ -353,8 +364,6 @@ public:
return m_auiEncounter[3];
case DATA_ECK_THE_FEROCIOUS_EVENT:
return m_auiEncounter[4];
- case DATA_ALIVE_RUIN_DWELLERS:
- return DwellerGUIDs.size();
}
return 0;
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 7f34e470c7e..a83f4feb70a 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/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
index 8cb7630e60e..8bc0ba1722a 100644
--- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
+++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
@@ -80,7 +80,7 @@ public:
switch (eventId)
{
case EVENT_VOID_BLAST:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
{
DoCast(target, SPELL_VOID_BLAST);
++VoidBlastCounter;
diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
index bd16fe9edd2..15c660b4ad7 100644
--- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
@@ -114,7 +114,6 @@ class boss_broggok : public CreatureScript
break;
}
}
-
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/Outland/zone_shattrath_city.cpp b/src/server/scripts/Outland/zone_shattrath_city.cpp
index 9a62cde005c..c2e7df19ca1 100644
--- a/src/server/scripts/Outland/zone_shattrath_city.cpp
+++ b/src/server/scripts/Outland/zone_shattrath_city.cpp
@@ -30,7 +30,6 @@ npc_shattrathflaskvendors
npc_zephyr
npc_kservant
npc_ishanah
-npc_khadgar
EndContentData */
#include "ScriptMgr.h"
@@ -469,73 +468,6 @@ public:
}
};
-/*######
-# npc_khadgar
-######*/
-
-#define KHADGAR_GOSSIP_1 "I've heard your name spoken only in whispers, mage. Who are you?"
-#define KHADGAR_GOSSIP_2 "Go on, please."
-#define KHADGAR_GOSSIP_3 "I see." //6th too this
-#define KHADGAR_GOSSIP_4 "What did you do then?"
-#define KHADGAR_GOSSIP_5 "What happened next?"
-#define KHADGAR_GOSSIP_7 "There was something else I wanted to ask you."
-
-class npc_khadgar : public CreatureScript
-{
-public:
- npc_khadgar() : CreatureScript("npc_khadgar") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- switch (action)
- {
- case GOSSIP_ACTION_INFO_DEF+1:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- player->SEND_GOSSIP_MENU(9876, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+2:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3);
- player->SEND_GOSSIP_MENU(9877, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+3:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4);
- player->SEND_GOSSIP_MENU(9878, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+4:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(9879, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+5:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6);
- player->SEND_GOSSIP_MENU(9880, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+6:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7);
- player->SEND_GOSSIP_MENU(9881, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+7:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->SEND_GOSSIP_MENU(9243, creature->GetGUID());
- break;
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(10211) != QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
-
- player->SEND_GOSSIP_MENU(9243, creature->GetGUID());
-
- return true;
- }
-};
-
void AddSC_shattrath_city()
{
new npc_raliq_the_drunk();
@@ -544,5 +476,4 @@ void AddSC_shattrath_city()
new npc_zephyr();
new npc_kservant();
new npc_ishanah();
- new npc_khadgar();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index ea90c13f747..d04b25147c7 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -33,7 +33,6 @@ npc_guardian 100% guardianAI used to prevent players from accessin
npc_garments_of_quests 80% NPC's related to all Garments of-quests 5621, 5624, 5625, 5648, 565
npc_injured_patient 100% patients for triage-quests (6622 and 6624)
npc_doctor 100% Gustaf Vanhowzen and Gregory Victor, quest 6622 and 6624 (Triage)
-npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy
npc_sayge 100% Darkmoon event fortune teller, buff player based on answers given
npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap
npc_shadowfiend 100% restore 5% of owner's mana when shadowfiend die from damage
@@ -1170,105 +1169,6 @@ public:
};
/*######
-## npc_mount_vendor
-######*/
-
-class npc_mount_vendor : public CreatureScript
-{
-public:
- npc_mount_vendor() : CreatureScript("npc_mount_vendor") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- bool canBuy = false;
- uint32 vendor = creature->GetEntry();
- uint8 race = player->getRace();
-
- switch (vendor)
- {
- case 384: //Katie Hunter
- case 1460: //Unger Statforth
- case 2357: //Merideth Carlson
- case 4885: //Gregor MacVince
- if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN)
- player->SEND_GOSSIP_MENU(5855, creature->GetGUID());
- else canBuy = true;
- break;
- case 1261: //Veron Amberstill
- if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF)
- player->SEND_GOSSIP_MENU(5856, creature->GetGUID());
- else canBuy = true;
- break;
- case 3362: //Ogunaro Wolfrunner
- if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC)
- player->SEND_GOSSIP_MENU(5841, creature->GetGUID());
- else canBuy = true;
- break;
- case 3685: //Harb Clawhoof
- if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN)
- player->SEND_GOSSIP_MENU(5843, creature->GetGUID());
- else canBuy = true;
- break;
- case 4730: //Lelanai
- if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF)
- player->SEND_GOSSIP_MENU(5844, creature->GetGUID());
- else canBuy = true;
- break;
- case 4731: //Zachariah Post
- if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER)
- player->SEND_GOSSIP_MENU(5840, creature->GetGUID());
- else canBuy = true;
- break;
- case 7952: //Zjolnir
- if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL)
- player->SEND_GOSSIP_MENU(5842, creature->GetGUID());
- else canBuy = true;
- break;
- case 7955: //Milli Featherwhistle
- if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME)
- player->SEND_GOSSIP_MENU(5857, creature->GetGUID());
- else canBuy = true;
- break;
- case 16264: //Winaestra
- if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF)
- player->SEND_GOSSIP_MENU(10305, creature->GetGUID());
- else canBuy = true;
- break;
- case 17584: //Torallius the Pack Handler
- if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI)
- player->SEND_GOSSIP_MENU(10239, creature->GetGUID());
- else canBuy = true;
- break;
- case 48510: //Kall Worthaton
- if (player->GetReputationRank(1133) != REP_EXALTED && race != RACE_GOBLIN)
- player->SEND_GOSSIP_MENU(17494, creature->GetGUID());
- else canBuy = true;
- break;
- }
-
- if (canBuy)
- {
- if (creature->IsVendor())
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
- }
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_TRADE)
- player->GetSession()->SendListInventory(creature->GetGUID());
-
- return true;
- }
-};
-
-/*######
## npc_sayge
######*/
@@ -2488,7 +2388,6 @@ void AddSC_npcs_special()
new npc_injured_patient();
new npc_garments_of_quests();
new npc_guardian();
- new npc_mount_vendor();
new npc_sayge();
new npc_steam_tonk();
new npc_tonk_mine();
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index 4e46ff0e3a1..abdf2a2cc3c 100644
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -57,14 +57,14 @@ m_connectionFlags(CONNECTION_ASYNC)
MySQLConnection::~MySQLConnection()
{
+ if (m_worker)
+ delete m_worker;
+
for (size_t i = 0; i < m_stmts.size(); ++i)
delete m_stmts[i];
if (m_Mysql)
mysql_close(m_Mysql);
-
- if (m_worker)
- delete m_worker;
}
void MySQLConnection::Close()
diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h
index 64665c2b198..c8f8e2dbd90 100644
--- a/src/server/shared/Networking/AsyncAcceptor.h
+++ b/src/server/shared/Networking/AsyncAcceptor.h
@@ -23,51 +23,68 @@
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));
+ }
- 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();
+ _socket.non_blocking(true);
+
+ mgrHandler(std::move(_socket));
}
catch (boost::system::system_error const& err)
{
- TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ TC_LOG_INFO("network", "Failed to initialize client's socket %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();
+ 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..043aee56504
--- /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..47bd7794a4c
--- /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 (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Stop();
+
+ Wait();
+ }
+
+ void Wait()
+ {
+ if (_threadCount != 0)
+ for (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Wait();
+ }
+
+ virtual void OnSocketOpen(tcp::socket&& sock)
+ {
+ size_t min = 0;
+
+ for (int32 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