From b426262d1ba634e44829228b9edfce390f8a5080 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 21 May 2016 11:25:58 +0200 Subject: Core/PacketIO: Fixed LFGuildApplications structure --- src/server/game/Server/Packets/GuildFinderPackets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Server/Packets/GuildFinderPackets.cpp b/src/server/game/Server/Packets/GuildFinderPackets.cpp index 137b5f29986..eb2f1178925 100644 --- a/src/server/game/Server/Packets/GuildFinderPackets.cpp +++ b/src/server/game/Server/Packets/GuildFinderPackets.cpp @@ -92,8 +92,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::GuildFinder::LFGuildAppli WorldPacket const* WorldPackets::GuildFinder::LFGuildApplications::Write() { - _worldPacket << uint32(Application.size()); _worldPacket << int32(NumRemaining); + _worldPacket << uint32(Application.size()); for (LFGuildApplicationData const& application : Application) _worldPacket << application; -- cgit v1.2.3 From 18d28e8dc603e4e55bf164edd6917d75e8a42774 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 22 May 2016 23:15:11 +0200 Subject: Core/PacketIO: Fixed sending OnHold pet cooldowns --- src/server/game/Spells/SpellHistory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index 7de2c2a9d46..82822a3b873 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -359,6 +359,8 @@ void SpellHistory::WritePacket(WorldPackets::Pet::PetSpells* petSpells) const if (categoryDuration.count() > 0) petSpellCooldown.CategoryDuration = uint32(categoryDuration.count()); } + else + petSpellCooldown.CategoryDuration = 0x80000000; petSpells->Cooldowns.push_back(petSpellCooldown); } @@ -382,7 +384,6 @@ void SpellHistory::WritePacket(WorldPackets::Pet::PetSpells* petSpells) const } } - void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/) { // init cooldown values -- cgit v1.2.3 From 40b38658c46ccabecc3b54588468d0846b35032d Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 23 May 2016 21:18:54 +0200 Subject: Core/DataStores: Fixed loading non-localized db2 strings --- src/server/shared/DataStores/DB2StorageLoader.cpp | 27 +++++++++++------------ 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp index d2be433806f..a1acd3b5eac 100644 --- a/src/server/shared/DataStores/DB2StorageLoader.cpp +++ b/src/server/shared/DataStores/DB2StorageLoader.cpp @@ -353,8 +353,7 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da std::size_t localizedStringFields = GetFormatLocalizedStringFieldCount(format); // each string field at load have array of string for each locale - std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*); + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount; char* stringHoldersPool = new char[stringHoldersPoolSize]; @@ -392,9 +391,9 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da char const*** slot = (char const***)(&dataTable[offset]); *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringFieldOffset]); if (format[x] == FT_STRING) - stringFieldOffset += stringHolderSize; + stringFieldOffset += sizeof(LocalizedString); else - ++stringFieldOffset; + stringFieldOffset += sizeof(char*); offset += sizeof(char*); break; @@ -497,19 +496,19 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); // we store flat holders pool as single memory block - size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format); + std::size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format); + std::size_t localizedStringFields = DB2FileLoader::GetFormatLocalizedStringFieldCount(format); // each string field at load have array of string for each locale - size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); if (stringFields) { - size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); + std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); stringHolders = new char[stringHoldersPoolSize]; // DB2 strings expected to have at least empty string - for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) + for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) ((char const**)stringHolders)[i] = nullStr; } else @@ -545,7 +544,7 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa { Field* fields = result->Fetch(); uint32 offset = 0; - uint32 stringFieldNumInRecord = 0; + uint32 stringFieldOffset = 0; uint32 indexValue; if (indexField >= 0) @@ -585,28 +584,28 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa case FT_STRING: { LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); - *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]); + *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); ASSERT(*slot); // Value in database in main table field must be for enUS locale if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) stringPool.push_back(str); - ++stringFieldNumInRecord; + stringFieldOffset += sizeof(LocalizedString); offset += sizeof(char*); break; } case FT_STRING_NOT_LOCALIZED: { char const** slot = (char const**)(&dataValue[offset]); - *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]); + *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + sizeof(LocalizedString) * stringFieldOffset]); ASSERT(*slot); // Value in database in main table field must be for enUS locale if (char* str = AddString(slot, fields[f].GetString())) stringPool.push_back(str); - ++stringFieldNumInRecord; + stringFieldOffset += sizeof(char*); offset += sizeof(char*); break; } -- cgit v1.2.3 From a6205e40350e283f81d3fcc6672bfdbd2b8aa4c7 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 24 May 2016 18:51:31 +0200 Subject: Core/Containers: Warning fixes and RandomResizeList with predicate optimization (cherry picked from commit 0fbfa8ead04a59f3eef70f4f2e454e318d895bd9) --- src/common/Utilities/Containers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index 554dcb1b3de..5edb245fd87 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -31,7 +31,7 @@ namespace Trinity namespace Containers { template - void RandomResizeList(std::list &list, uint32 size) + void RandomResizeList(std::list& list, uint32 size) { uint32 list_size = uint32(list.size()); @@ -56,7 +56,7 @@ namespace Trinity if (size) RandomResizeList(listCopy, size); - list = listCopy; + list = std::move(listCopy); } /* -- cgit v1.2.3 From 6b30b88910c12e5b1619a1a086b7014e95055a30 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 25 May 2016 20:55:28 +0200 Subject: Core/Bnet: Order account list by id when the bnet account has more than 1 game account attached --- src/server/database/Database/Implementation/LoginDatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index e37258001ea..249839c079b 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -119,7 +119,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", " BnetGameAccountInfo " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account" - " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? AND ba.sha_pass_hash = ?", CONNECTION_SYNCH); + " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? AND ba.sha_pass_hash = ? ORDER BY a.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_ACCOUNT_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_ASYNC); -- cgit v1.2.3 From b539ac6afafbddcb75855511d66d97bbc2e95c30 Mon Sep 17 00:00:00 2001 From: Shocker Date: Thu, 26 May 2016 13:09:56 +0300 Subject: Core/GameObjects: Add isUse parameter to GossipHello for distinction between CMSG_GAMEOBJECT_USE and CMSG_GAMEOBJECT_REPORT_USE --- src/server/game/AI/CoreAI/GameObjectAI.h | 2 +- src/server/game/AI/SmartScripts/SmartAI.cpp | 2 +- src/server/game/AI/SmartScripts/SmartAI.h | 2 +- src/server/game/Entities/GameObject/GameObject.cpp | 2 +- src/server/game/Handlers/SpellHandler.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 2 +- .../Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp | 4 +++- .../Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp | 5 ++++- src/server/scripts/World/go_scripts.cpp | 9 ++++----- 9 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 7a2f23ac804..6d02f97e0ec 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -47,7 +47,7 @@ class TC_GAME_API GameObjectAI static int Permissible(GameObject const* go); - virtual bool GossipHello(Player* /*player*/) { return false; } + virtual bool GossipHello(Player* /*player*/, bool /*isUse*/) { return false; } virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { return false; } virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { return false; } virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) { return false; } diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 914a476cf7d..5cda5fce674 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -840,7 +840,7 @@ void SmartGameObjectAI::Reset() } // Called when a player opens a gossip dialog with the gameobject. -bool SmartGameObjectAI::GossipHello(Player* player) +bool SmartGameObjectAI::GossipHello(Player* player, bool /*isUse*/) { TC_LOG_DEBUG("scripts.ai", "SmartGameObjectAI::GossipHello"); GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player, 0, 0, false, NULL, go); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index aa7c9ace0b3..67a7bd4c330 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -242,7 +242,7 @@ class TC_GAME_API SmartGameObjectAI : public GameObjectAI SmartScript* GetScript() { return &mScript; } static int Permissible(const GameObject* g); - bool GossipHello(Player* player) override; + bool GossipHello(Player* player, bool isUse) override; bool GossipSelect(Player* player, uint32 sender, uint32 action) override; bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) override; bool QuestAccept(Player* player, Quest const* quest) override; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 42d7ff404db..a43ab95c80c 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1247,7 +1247,7 @@ void GameObject::Use(Unit* user) if (sScriptMgr->OnGossipHello(playerUser, this)) return; - if (AI()->GossipHello(playerUser)) + if (AI()->GossipHello(playerUser, true)) return; } diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 7d639d57f80..45ce6399c24 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -235,7 +235,7 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjRe if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid)) { - if (go->AI()->GossipHello(_player)) + if (go->AI()->GossipHello(_player, false)) return; _player->UpdateCriteria(CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d605e1d8679..58f1f24e584 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1721,7 +1721,7 @@ void Spell::SendLoot(ObjectGuid guid, LootType loottype) if (sScriptMgr->OnGossipHello(player, gameObjTarget)) return; - if (gameObjTarget->AI()->GossipHello(player)) + if (gameObjTarget->AI()->GossipHello(player, true)) return; switch (gameObjTarget->GetGoType()) diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 8c68fe4cc18..9d7c41ffd7b 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -1353,8 +1353,10 @@ class go_twilight_portal : public GameObjectScript } } - bool GossipHello(Player* player) override + bool GossipHello(Player* player, bool isUse) override { + if (!isUse) + return true; if (_spellId != 0) player->CastSpell(player, _spellId, true); return true; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 0d8f9a6bce1..33afada15fd 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -977,8 +977,11 @@ class go_celestial_planetarium_access : public GameObjectScript { } - bool GossipHello(Player* player) override + bool GossipHello(Player* player, bool isUse) override { + if (!isUse) + return true; + if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE)) return true; diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 0e9a972a3fb..c9481f2e6b8 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -834,12 +834,11 @@ class go_soulwell : public GameObjectScript { } - /// Due to the fact that this GameObject triggers CMSG_GAMEOBJECT_USE - /// _and_ CMSG_GAMEOBJECT_REPORT_USE, this GossipHello hook is called - /// twice. The script's handling is fine as it won't remove two charges - /// on the well. We have to find how to segregate REPORT_USE and USE. - bool GossipHello(Player* player) override + bool GossipHello(Player* player, bool isUse) override { + if (!isUse) + return true; + Unit* owner = go->GetOwner(); if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !player->IsInSameRaidWith(owner->ToPlayer())) return true; -- cgit v1.2.3 From 6c71c8694f91f6254e8a913f0550e4ff78cb6875 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 26 May 2016 14:47:36 +0200 Subject: Core/Auras: Implemented SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE, SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE, SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN and SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN --- src/server/game/Spells/Auras/SpellAuraDefines.h | 8 ++++---- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 8 ++++---- src/server/game/Spells/Spell.cpp | 17 +++++++++++------ src/server/game/Spells/SpellHistory.cpp | 22 +++++++++++++++++----- 4 files changed, 36 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 5130ebd7876..d781a8822b8 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -404,7 +404,7 @@ enum AuraType SPELL_AURA_MOD_AUTOATTACK_DAMAGE = 344, // NYI SPELL_AURA_BYPASS_ARMOR_FOR_CASTER = 345, SPELL_AURA_ENABLE_ALT_POWER = 346, // NYI - SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE = 347, // NYI + SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE = 347, SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT = 348, SPELL_AURA_MOD_CURRENCY_GAIN = 349, SPELL_AURA_MOD_GATHERING_ITEMS_GAINED_PERCENT = 350, // NYI @@ -437,7 +437,7 @@ enum AuraType SPELL_AURA_CAST_WHILE_WALKING_2 = 377, // NYI SPELL_AURA_378 = 378, SPELL_AURA_379 = 379, - SPELL_AURA_380 = 380, + SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE = 380, // Allows melee abilities to benefit from haste GCD reduction SPELL_AURA_381 = 381, SPELL_AURA_MOD_PET_STAT_PCT = 382, // NYI SPELL_AURA_IGNORE_SPELL_COOLDOWN = 383, // NYI @@ -473,8 +473,8 @@ enum AuraType SPELL_AURA_413 = 413, SPELL_AURA_414 = 414, SPELL_AURA_415 = 415, - SPELL_AURA_MOD_COOLDOWN_BY_HASTE_EFFECTS = 416, // NYI - SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_EFFECTS = 417, // NYI + SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN = 416, + SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN = 417, SPELL_AURA_MOD_MAX_POWER = 418, // NYI SPELL_AURA_MOD_BASE_MANA_PCT = 419, SPELL_AURA_MOD_BATTLE_PET_XP_PCT = 420, // NYI diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a35d5e37b47..911db589f2d 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -406,7 +406,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //344 SPELL_AURA_MOD_AUTOATTACK_DAMAGE &AuraEffect::HandleNoImmediateEffect, //345 SPELL_AURA_BYPASS_ARMOR_FOR_CASTER &AuraEffect::HandleEnableAltPower, //346 SPELL_AURA_ENABLE_ALT_POWER - &AuraEffect::HandleNULL, //347 SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE + &AuraEffect::HandleNoImmediateEffect, //347 SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE implemented in SpellHistory::StartCooldown &AuraEffect::HandleNoImmediateEffect, //348 SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT implemented in WorldSession::HandleLootMoneyOpcode &AuraEffect::HandleNoImmediateEffect, //349 SPELL_AURA_MOD_CURRENCY_GAIN implemented in Player::ModifyCurrency &AuraEffect::HandleNULL, //350 SPELL_AURA_MOD_GATHERING_ITEMS_GAINED_PERCENT @@ -439,7 +439,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //377 SPELL_AURA_CAST_WHILE_WALKING_2 &AuraEffect::HandleNULL, //378 &AuraEffect::HandleNULL, //379 - &AuraEffect::HandleNULL, //380 + &AuraEffect::HandleNoImmediateEffect, //380 SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE implemented in Spell::TriggerGlobalCooldown &AuraEffect::HandleNULL, //381 &AuraEffect::HandleNULL, //382 SPELL_AURA_MOD_PET_STAT_PCT &AuraEffect::HandleNULL, //383 SPELL_AURA_IGNORE_SPELL_COOLDOWN @@ -475,8 +475,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //413 &AuraEffect::HandleNULL, //414 &AuraEffect::HandleNULL, //415 - &AuraEffect::HandleNULL, //416 SPELL_AURA_MOD_COOLDOWN_BY_HASTE_EFFECTS - &AuraEffect::HandleNULL, //417 SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_EFFECTS + &AuraEffect::HandleNoImmediateEffect, //416 SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN implemented in SpellHistory::StartCooldown + &AuraEffect::HandleNoImmediateEffect, //417 SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN implemented in Spell::TriggerGlobalCooldown &AuraEffect::HandleNULL, //418 SPELL_AURA_MOD_MAX_POWER &AuraEffect::HandleAuraModIncreaseBaseManaPercent, //419 SPELL_AURA_MOD_BASE_MANA_PCT &AuraEffect::HandleNULL, //420 SPELL_AURA_MOD_BATTLE_PET_XP_PCT diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index dac9b82549c..aa02dfa3f63 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7450,7 +7450,7 @@ bool Spell::HasGlobalCooldown() const void Spell::TriggerGlobalCooldown() { int32 gcd = m_spellInfo->StartRecoveryTime; - if (!gcd) + if (!gcd || !m_spellInfo->StartRecoveryCategory) return; // Only players or controlled units have global cooldown @@ -7470,12 +7470,17 @@ void Spell::TriggerGlobalCooldown() if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this); + bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || + m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED || + m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || + m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY); + // Apply haste rating - gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); - if (gcd < MIN_GCD) - gcd = MIN_GCD; - else if (gcd > MAX_GCD) - gcd = MAX_GCD; + if (gcd > MIN_GCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell) || m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE, m_spellInfo))) + gcd = std::min(std::max(int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_HASTE)), MIN_GCD), MAX_GCD); + + if (gcd > MIN_GCD && m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN, m_spellInfo)) + gcd = std::min(std::max(int32(float(gcd) * m_caster->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN)), MIN_GCD), MAX_GCD); } m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd); diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index 82822a3b873..fe56eb3c01b 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -330,7 +330,7 @@ void SpellHistory::WritePacket(WorldPackets::Spells::SendSpellCharges* sendSpell WorldPackets::Spells::SpellChargeEntry chargeEntry; chargeEntry.Category = p.first; chargeEntry.NextRecoveryTime = uint32(cooldownDuration.count()); - chargeEntry.ConsumedCharges = p.second.size(); + chargeEntry.ConsumedCharges = uint8(p.second.size()); sendSpellCharges->Entries.push_back(chargeEntry); } } @@ -377,7 +377,7 @@ void SpellHistory::WritePacket(WorldPackets::Pet::PetSpells* petSpells) const WorldPackets::Pet::PetSpellHistory petChargeEntry; petChargeEntry.CategoryID = p.first; petChargeEntry.RecoveryTime = uint32(cooldownDuration.count()); - petChargeEntry.ConsumedCharges = p.second.size(); + petChargeEntry.ConsumedCharges = int8(p.second.size()); petSpells->SpellHistory.push_back(petChargeEntry); } @@ -422,6 +422,18 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell); } + if (_owner->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE, spellInfo)) + { + cooldown = int32(cooldown * _owner->GetFloatValue(UNIT_MOD_CAST_HASTE)); + categoryCooldown = int32(categoryCooldown * _owner->GetFloatValue(UNIT_MOD_CAST_HASTE)); + } + + if (_owner->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN, spellInfo)) + { + cooldown = int32(cooldown * _owner->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN)); + categoryCooldown = int32(categoryCooldown * _owner->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN)); + } + if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN)) { // Apply SPELL_AURA_MOD_COOLDOWN only to own spells @@ -735,7 +747,7 @@ void SpellHistory::RestoreCharge(SpellCategoryEntry const* chargeCategoryEntry) setSpellCharges.Category = chargeCategoryEntry->ID; if (!itr->second.empty()) setSpellCharges.NextRecoveryTime = uint32(std::chrono::duration_cast(itr->second.front().RechargeEnd - Clock::now()).count()); - setSpellCharges.ConsumedCharges = itr->second.size(); + setSpellCharges.ConsumedCharges = uint8(itr->second.size()); setSpellCharges.IsPet = player != _owner; player->SendDirectMessage(setSpellCharges.Write()); @@ -807,7 +819,7 @@ int32 SpellHistory::GetChargeRecoveryTime(SpellCategoryEntry const* chargeCatego int32 recoveryTime = chargeCategoryEntry->ChargeRecoveryTime; recoveryTime += _owner->GetTotalAuraModifierByMiscValue(SPELL_AURA_CHARGE_RECOVERY_MOD, chargeCategoryEntry->ID); - float recoveryTimeF = recoveryTime; + float recoveryTimeF = float(recoveryTime); recoveryTimeF *= _owner->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER, chargeCategoryEntry->ID); if (_owner->HasAuraType(SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE)) @@ -928,7 +940,7 @@ void SpellHistory::RestoreCooldownStateAfterDuel() for (auto const& c : _spellCooldowns) { Clock::time_point now = Clock::now(); - uint32 cooldownDuration = c.second.CooldownEnd > now ? std::chrono::duration_cast(c.second.CooldownEnd - now).count() : 0; + uint32 cooldownDuration = uint32(c.second.CooldownEnd > now ? std::chrono::duration_cast(c.second.CooldownEnd - now).count() : 0); // cooldownDuration must be between 0 and 10 minutes in order to avoid any visual bugs if (cooldownDuration <= 0 || cooldownDuration > 10 * MINUTE * IN_MILLISECONDS || c.second.OnHold) -- cgit v1.2.3 From bc1a81747ae032bc2ae3681d99f5f6058d20caff Mon Sep 17 00:00:00 2001 From: myran2 Date: Fri, 29 Apr 2016 11:49:07 -0400 Subject: Core/Pets: Implemented pet specializations (#17058) * Use prepared statements in Pet::SavePetToDB * Add support for resetting all of a player's pet specializations * Send one big spell unlearn/learn packet instead of lots of small ones * Implemented Adaptation talent --- sql/base/characters_database.sql | 3 +- .../characters/6.x/2016_05_26_00_characters.sql | 1 + .../Database/Implementation/CharacterDatabase.cpp | 12 +- .../Database/Implementation/CharacterDatabase.h | 3 + src/server/game/Entities/Pet/Pet.cpp | 379 +++++++++------------ src/server/game/Entities/Pet/Pet.h | 18 +- src/server/game/Entities/Player/Player.cpp | 3 +- src/server/game/Handlers/CharacterHandler.cpp | 12 +- src/server/game/Handlers/PetHandler.cpp | 34 ++ src/server/game/Server/Packets/PetPackets.cpp | 13 + src/server/game/Server/Packets/PetPackets.h | 21 ++ src/server/game/Server/Protocol/Opcodes.cpp | 4 +- src/server/game/Server/WorldSession.h | 2 + src/server/game/Spells/Auras/SpellAuraEffects.cpp | 42 ++- src/server/game/Spells/Auras/SpellAuraEffects.h | 2 +- src/server/game/Spells/SpellEffects.cpp | 4 - 16 files changed, 294 insertions(+), 259 deletions(-) create mode 100644 sql/updates/characters/6.x/2016_05_26_00_characters.sql (limited to 'src') diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index bccc4176530..2d5104196b6 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1071,6 +1071,7 @@ CREATE TABLE `character_pet` ( `curmana` int(10) unsigned NOT NULL DEFAULT '0', `savetime` int(10) unsigned NOT NULL DEFAULT '0', `abdata` text, + `specialization` smallint(5) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `owner` (`owner`), KEY `idx_slot` (`slot`) @@ -3109,7 +3110,7 @@ CREATE TABLE `updates` ( LOCK TABLES `updates` WRITE; /*!40000 ALTER TABLE `updates` DISABLE KEYS */; -INSERT INTO `updates` VALUES ('2014_10_20_00_characters.sql','A5882DA0979CF4DAE33DA011EBAA006C24BE7230','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_00_characters.sql','E2AC4758133EE19B7F08464A445802154D1261C8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_01_characters.sql','20029E6323D9773B32C34D84FFED1711CC60F09F','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_02_characters.sql','8A7A16886EE71E7ACDDB3DDA6D0ECAC2FD2FDCA8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_24_00_characters.sql','D008FE81AE844FCA686439D6ECC5108FB0DD1EB9','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_25_00_characters.sql','A39C7BE46686B54776BDAB9D7A882D91EDEC51A4','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_26_00_characters.sql','C787954CC35FE34B4101FDE6527F14C027F4947C','ARCHIVED','2015-03-21 15:55:55',0),('2014_11_12_00_characters.sql','B160BB2313F1BD5F3B076A5A9279DC10D4796E34','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_23_00_characters.sql','3D9D648B2387B357F4BD090B33F80682F7924882','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_28_00_characters.sql','5362922FF4483A336311D73082A5727309CD9219','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_31_00_characters.sql','498DDF2DD936CF156D74A8208DC93DCE9FCAB5AA','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_02_00_characters.sql','E5940BE836F253982E07930120422E598D08BDE1','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_10_00_characters.sql','30796056C8623699B2FE1BF626A19D38262E9284','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_16_00_characters.sql','96642760A54C8D799AAFE438049A63AA521656F2','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_27_00_characters.sql','EB710E3EB9F2CAFD84AB62CDC84E898403A80A4F','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_00_characters.sql','405BEB4ED207DC6076442A37EE2AFB1F21E274A0','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_01_characters.sql','35F582D4F33BF55D1685A1BA89273ED895FD09C5','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_17_00_characters.sql','8D21FC5A55BF8B55D6DCDCE5F02CF2B640230E94','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_10_00_characters.sql','E565B89B145C340067742DFF2DEF1B74F5F1BD4E','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_01_characters.sql','20BD68468C57FCF7E665B4DA185DCD52FACE8B3F','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_02_characters.sql','0296995DCD3676BA9AE6024CA7C91C5F39D927A3','ARCHIVED','2015-03-21 15:56:46',0),('2015_03_29_00_characters.sql','95D6A46BB746A8BD3EE3FE2086DF1A07F7C33B92','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_21_00_characters.sql','F2032B9BF4EDA7EDE5065554724ED392FD91657D','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_28_00_characters.sql','949F62DB3A3461D420A1230ECF7A6A3ED6435703','ARCHIVED','2015-05-02 15:43:06',0),('2015_05_08_00_characters.sql','0F14B7821618D1C872625B6EDDAA9A667B211167','ARCHIVED','2015-07-10 19:32:17',0),('2015_05_22_00_characters.sql','65B82152413FAB23BE413656E59A486A74447FF7','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_08_00_characters.sql','DAB25360ACB5244C8F8E6214CF6BD97160588A5B','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_11_00_characters.sql','B421B6C0E57BD0FD587071358863D9DABF4BA849','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_12_00_characters.sql','E98E7FD61EF6426E7EDE8ED9AD8C15D8D7132589','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_28_00_characters.sql','0711BC3A658D189EF71B0CB68DCFF2E9B781C4A0','ARCHIVED','2015-07-29 16:23:56',0),('2015_08_08_00_characters.sql','EA12BB2DC24FAF2300A96D0888A45BBEA158D5DC','ARCHIVED','2015-08-08 16:34:07',0),('2015_08_12_00_characters.sql','4FD7F89FE5DA51D4E0C33E520719986AA3EBD31B','ARCHIVED','2015-08-12 12:35:20',0),('2015_09_05_00_characters.sql','4C22BB29365BE4B6B95E64DAD84B63CA002304EA','ARCHIVED','2015-09-05 12:35:20',0),('2015_09_09_00_characters.sql','AFC32E693BC17CFD9A17919FE5317B8FE337ACAD','ARCHIVED','2015-09-09 12:35:20',0),('2015_09_10_00_characters.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-09-10 22:50:42',0),('2015_10_16_00_characters.sql','E3A3FFF0CB42F04A8DCF0CE4362143C16E2083AF','ARCHIVED','2015-10-15 21:54:11',0),('2015_11_06_00_characters_2015_10_12_00.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-11-06 23:43:27',0),('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',15),('2015_11_23_00_characters.sql','9FC828E9E48E8E2E9B99A5A0073D6614C5BFC6B5','ARCHIVED','2015-11-22 23:27:34',0),('2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-01-04 23:07:40',0),('2016_04_05_00_characters_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-04-05 20:34:41',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','RELEASED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','RELEASED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','RELEASED','2016-05-07 00:00:00',0); +INSERT INTO `updates` VALUES ('2014_10_20_00_characters.sql','A5882DA0979CF4DAE33DA011EBAA006C24BE7230','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_00_characters.sql','E2AC4758133EE19B7F08464A445802154D1261C8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_01_characters.sql','20029E6323D9773B32C34D84FFED1711CC60F09F','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_02_characters.sql','8A7A16886EE71E7ACDDB3DDA6D0ECAC2FD2FDCA8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_24_00_characters.sql','D008FE81AE844FCA686439D6ECC5108FB0DD1EB9','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_25_00_characters.sql','A39C7BE46686B54776BDAB9D7A882D91EDEC51A4','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_26_00_characters.sql','C787954CC35FE34B4101FDE6527F14C027F4947C','ARCHIVED','2015-03-21 15:55:55',0),('2014_11_12_00_characters.sql','B160BB2313F1BD5F3B076A5A9279DC10D4796E34','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_23_00_characters.sql','3D9D648B2387B357F4BD090B33F80682F7924882','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_28_00_characters.sql','5362922FF4483A336311D73082A5727309CD9219','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_31_00_characters.sql','498DDF2DD936CF156D74A8208DC93DCE9FCAB5AA','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_02_00_characters.sql','E5940BE836F253982E07930120422E598D08BDE1','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_10_00_characters.sql','30796056C8623699B2FE1BF626A19D38262E9284','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_16_00_characters.sql','96642760A54C8D799AAFE438049A63AA521656F2','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_27_00_characters.sql','EB710E3EB9F2CAFD84AB62CDC84E898403A80A4F','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_00_characters.sql','405BEB4ED207DC6076442A37EE2AFB1F21E274A0','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_01_characters.sql','35F582D4F33BF55D1685A1BA89273ED895FD09C5','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_17_00_characters.sql','8D21FC5A55BF8B55D6DCDCE5F02CF2B640230E94','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_10_00_characters.sql','E565B89B145C340067742DFF2DEF1B74F5F1BD4E','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_01_characters.sql','20BD68468C57FCF7E665B4DA185DCD52FACE8B3F','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_02_characters.sql','0296995DCD3676BA9AE6024CA7C91C5F39D927A3','ARCHIVED','2015-03-21 15:56:46',0),('2015_03_29_00_characters.sql','95D6A46BB746A8BD3EE3FE2086DF1A07F7C33B92','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_21_00_characters.sql','F2032B9BF4EDA7EDE5065554724ED392FD91657D','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_28_00_characters.sql','949F62DB3A3461D420A1230ECF7A6A3ED6435703','ARCHIVED','2015-05-02 15:43:06',0),('2015_05_08_00_characters.sql','0F14B7821618D1C872625B6EDDAA9A667B211167','ARCHIVED','2015-07-10 19:32:17',0),('2015_05_22_00_characters.sql','65B82152413FAB23BE413656E59A486A74447FF7','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_08_00_characters.sql','DAB25360ACB5244C8F8E6214CF6BD97160588A5B','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_11_00_characters.sql','B421B6C0E57BD0FD587071358863D9DABF4BA849','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_12_00_characters.sql','E98E7FD61EF6426E7EDE8ED9AD8C15D8D7132589','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_28_00_characters.sql','0711BC3A658D189EF71B0CB68DCFF2E9B781C4A0','ARCHIVED','2015-07-29 16:23:56',0),('2015_08_08_00_characters.sql','EA12BB2DC24FAF2300A96D0888A45BBEA158D5DC','ARCHIVED','2015-08-08 16:34:07',0),('2015_08_12_00_characters.sql','4FD7F89FE5DA51D4E0C33E520719986AA3EBD31B','ARCHIVED','2015-08-12 12:35:20',0),('2015_09_05_00_characters.sql','4C22BB29365BE4B6B95E64DAD84B63CA002304EA','ARCHIVED','2015-09-05 12:35:20',0),('2015_09_09_00_characters.sql','AFC32E693BC17CFD9A17919FE5317B8FE337ACAD','ARCHIVED','2015-09-09 12:35:20',0),('2015_09_10_00_characters.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-09-10 22:50:42',0),('2015_10_16_00_characters.sql','E3A3FFF0CB42F04A8DCF0CE4362143C16E2083AF','ARCHIVED','2015-10-15 21:54:11',0),('2015_11_06_00_characters_2015_10_12_00.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-11-06 23:43:27',0),('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',15),('2015_11_23_00_characters.sql','9FC828E9E48E8E2E9B99A5A0073D6614C5BFC6B5','ARCHIVED','2015-11-22 23:27:34',0),('2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-01-04 23:07:40',0),('2016_04_05_00_characters_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-04-05 20:34:41',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','RELEASED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','RELEASED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','RELEASED','2016-05-07 00:00:00',0),('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','RELEASED','2016-05-26 17:06:16',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/6.x/2016_05_26_00_characters.sql b/sql/updates/characters/6.x/2016_05_26_00_characters.sql new file mode 100644 index 00000000000..41a5222ac16 --- /dev/null +++ b/sql/updates/characters/6.x/2016_05_26_00_characters.sql @@ -0,0 +1 @@ +ALTER TABLE `character_pet` ADD `specialization` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `abdata`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index a7e7394fc87..24f798f7f98 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -649,10 +649,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " "VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND entry = ? AND (slot = ? OR slot > ?)", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PET_BY_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?) ", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND slot = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND entry = ? AND (slot = ? OR slot > ?)", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PET_BY_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?) ", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND slot = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ? AND id <> ?", CONNECTION_ASYNC); @@ -660,6 +660,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM `pet_spell` WHERE `guid` in (SELECT `id` FROM `character_pet` WHERE owner=?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_PET_SPECS_BY_OWNER, "UPDATE character_pet SET specialization = 0 WHERE owner=?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); // PvPstats PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 18faea4c5b0..459b0dfe98d 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -559,6 +559,9 @@ enum CharacterDatabaseStatements CHAR_UPD_CHAR_PET_SLOT_BY_ID, CHAR_DEL_CHAR_PET_BY_ID, CHAR_DEL_CHAR_PET_BY_SLOT, + CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, + CHAR_UPD_PET_SPECS_BY_OWNER, + CHAR_INS_PET, CHAR_SEL_ITEMCONTAINER_ITEMS, CHAR_DEL_ITEMCONTAINER_ITEMS, diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index deefff1423b..4678d3d0455 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -37,9 +37,9 @@ #define PET_XP_FACTOR 0.05f Pet::Pet(Player* owner, PetType type) : - Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), + Guardian(NULL, owner, true), m_removed(false), m_petType(type), m_duration(0), m_loading(false), m_groupUpdateMask(0), - m_declinedname(NULL) + m_declinedname(NULL), m_petSpecialization(0) { ASSERT(GetOwner()); @@ -312,8 +312,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c owner->SetMinion(this, true); map->AddToMap(this->ToCreature()); - InitTalentForLevel(); // set original talents points before spell loading - uint32 timediff = uint32(time(NULL) - fields[13].GetUInt32()); _LoadAuras(timediff); @@ -323,23 +321,28 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c m_charmInfo->LoadPetActionBar(fields[12].GetString()); _LoadSpells(); - InitTalentForLevel(); // re-init to check talent count _LoadSpellCooldowns(); LearnPetPassives(); InitLevelupSpellsForLevel(); CastPetAuras(current); } - CleanupActionBar(); // remove unknown spells from action bar after load - TC_LOG_DEBUG("entities.pet", "New Pet has %s", GetGUID().ToString().c_str()); - owner->PetSpellInitialize(); + uint16 specId = fields[16].GetUInt16(); + if (ChrSpecializationEntry const* petSpec = sChrSpecializationStore.LookupEntry(specId)) + specId = sChrSpecializationByIndexStore[owner->HasAuraType(SPELL_AURA_OVERRIDE_PET_SPECS) ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0][petSpec->OrderIndex]->ID; - SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + SetSpecialization(specId); - // TODO: 6.x remove/update pet talents - //owner->SendTalentsInfoData(true); + // The SetSpecialization function will run these functions if the pet's spec is not 0 + if (!GetSpecialization()) + { + CleanupActionBar(); // remove unknown spells from action bar after load + owner->PetSpellInitialize(); + } + + SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); if (getPetType() == HUNTER_PET) { @@ -415,8 +418,6 @@ void Pet::SavePetToDB(PetSaveMode mode) if (mode >= PET_SAVE_AS_CURRENT) { ObjectGuid::LowType ownerLowGUID = GetOwnerGUID().GetCounter(); - std::string name = m_name; - CharacterDatabase.EscapeString(name); trans = CharacterDatabase.BeginTransaction(); // remove current data @@ -445,34 +446,28 @@ void Pet::SavePetToDB(PetSaveMode mode) } // save pet - std::ostringstream ss; - ss << "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType) " - << "VALUES (" - << m_charmInfo->GetPetNumber() << ',' - << GetEntry() << ',' - << ownerLowGUID << ',' - << GetNativeDisplayId() << ',' - << uint32(getLevel()) << ',' - << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ',' - << uint32(GetReactState()) << ',' - << uint32(mode) << ", '" - << name.c_str() << "', " - << uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1) << ',' - << curhealth << ',' - << curmana << ", '"; - - for (uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) - { - ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' ' - << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << ' '; - }; - - ss << "', " - << time(NULL) << ',' - << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ',' - << uint32(getPetType()) << ')'; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET); + stmt->setUInt32(0, m_charmInfo->GetPetNumber()); + stmt->setUInt32(1, GetEntry()); + stmt->setUInt64(2, ownerLowGUID); + stmt->setUInt32(3, GetNativeDisplayId()); + stmt->setUInt8(4, getLevel()); + stmt->setUInt32(5, GetUInt32Value(UNIT_FIELD_PETEXPERIENCE)); + stmt->setUInt8(6, GetReactState()); + stmt->setInt16(7, mode); + stmt->setString(8, m_name); + stmt->setUInt8(9, HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1); + stmt->setUInt32(10, curhealth); + stmt->setUInt32(11, curmana); + + stmt->setString(12, GenerateActionBarData()); + + stmt->setUInt32(13, time(NULL)); + stmt->setUInt32(14, GetUInt32Value(UNIT_CREATED_BY_SPELL)); + stmt->setUInt8(15, getPetType()); + stmt->setUInt16(16, m_petSpecialization); + trans->Append(stmt); - trans->Append(ss.str().c_str()); CharacterDatabase.CommitTransaction(trans); } // delete @@ -724,7 +719,6 @@ void Pet::GivePetLevel(uint8 level) InitStatsForLevel(level); InitLevelupSpellsForLevel(); - InitTalentForLevel(); } bool Pet::CreateBaseAtCreature(Creature* creature) @@ -1436,6 +1430,22 @@ bool Pet::learnSpell(uint32 spell_id) return true; } +void Pet::learnSpells(std::vector const& spellIds) +{ + WorldPackets::Pet::PetLearnedSpells packet; + + for (uint32 spell : spellIds) + { + if (!addSpell(spell)) + continue; + + packet.Spells.push_back(spell); + } + + if (!m_loading) + GetOwner()->GetSession()->SendPacket(packet.Write()); +} + void Pet::InitLevelupSpellsForLevel() { uint8 level = getLevel(); @@ -1488,6 +1498,22 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab) return false; } +void Pet::unlearnSpells(std::vector const& spellIds, bool learn_prev, bool clear_ab) +{ + WorldPackets::Pet::PetUnlearnedSpells packet; + + for (uint32 spell : spellIds) + { + if (!removeSpell(spell, learn_prev, clear_ab)) + continue; + + packet.Spells.push_back(spell); + } + + if (!m_loading) + GetOwner()->GetSession()->SendPacket(packet.Write()); +} + bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { PetSpellMap::iterator itr = m_spells.find(spell_id); @@ -1513,7 +1539,7 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) } // if remove last rank or non-ranked then update action bar at server and client if need - if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id)) + if (m_charmInfo->RemoveSpellFromActionBar(spell_id) && !learn_prev && clear_ab) { if (!m_loading) GetOwner()->PetSpellInitialize(); // need update action bar for last removed rank @@ -1549,182 +1575,6 @@ void Pet::InitPetCreateSpells() CastPetAuras(false); } -bool Pet::resetTalents() -{ - /* TODO: 6.x remove pet talents - Player* player = GetOwner(); - - // not need after this call - if (player->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - player->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); - - CreatureTemplate const* ci = GetCreatureTemplate(); - if (!ci) - return false; - // Check pet talent type - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); - if (!pet_family || pet_family->PetTalentType < 0) - return false; - - uint8 level = getLevel(); - uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); - - if (m_usedTalentCount == 0) - { - SetFreeTalentPoints(talentPointsForLevel); - return false; - } - - for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) - { - TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); - - if (!talentInfo) - continue; - - TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); - - if (!talentTabInfo) - continue; - - // unlearn only talents for pets family talent type - if (!((1 << pet_family->PetTalentType) & talentTabInfo->petTalentMask)) - continue; - - for (uint8 j = 0; j < MAX_TALENT_RANK; ++j) - { - for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end();) - { - if (itr->second.state == PETSPELL_REMOVED) - { - ++itr; - continue; - } - // remove learned spells (all ranks) - uint32 itrFirstId = sSpellMgr->GetFirstSpellInChain(itr->first); - - // unlearn if first rank is talent or learned by talent - if (itrFirstId == talentInfo->RankID[j] || sSpellMgr->IsSpellLearnToSpell(talentInfo->RankID[j], itrFirstId)) - { - unlearnSpell(itr->first, false); - itr = m_spells.begin(); - continue; - } - else - ++itr; - } - } - } - - SetFreeTalentPoints(talentPointsForLevel); - - if (!m_loading) - player->PetSpellInitialize();*/ - return true; -} - -void Pet::resetTalentsForAllPetsOf(Player* /*owner*/, Pet* /*onlinePet*/ /*= NULL*/) -{ - /* TODO: 6.x remove pet talents - // not need after this call - if (owner->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - owner->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true); - - // reset for online - if (onlinePet) - onlinePet->resetTalents(); - - // now need only reset for offline pets (all pets except online case) - uint32 exceptPetNumber = onlinePet ? onlinePet->GetCharmInfo()->GetPetNumber() : 0; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PET); - stmt->setUInt64(0, owner->GetGUID().GetCounter()); - stmt->setUInt32(1, exceptPetNumber); - PreparedQueryResult resultPets = CharacterDatabase.Query(stmt); - - // no offline pets - if (!resultPets) - return; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_LIST); - stmt->setUInt64(0, owner->GetGUID().GetCounter()); - stmt->setUInt32(1, exceptPetNumber); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (!result) - return; - - bool need_comma = false; - std::ostringstream ss; - ss << "DELETE FROM pet_spell WHERE guid IN ("; - - do - { - Field* fields = resultPets->Fetch(); - - uint32 id = fields[0].GetUInt32(); - - if (need_comma) - ss << ','; - - ss << id; - - need_comma = true; - } while (resultPets->NextRow()); - - ss << ") AND spell IN ("; - - bool need_execute = false; - do - { - Field* fields = result->Fetch(); - - uint32 spell = fields[0].GetUInt32(); - - if (!GetTalentSpellCost(spell)) - continue; - - if (need_execute) - ss << ','; - - ss << spell; - - need_execute = true; - } - while (result->NextRow()); - - if (!need_execute) - return; - - ss << ')'; - - CharacterDatabase.Execute(ss.str().c_str());*/ -} - -void Pet::InitTalentForLevel() -{ - /* TODO: 6.x remove/update pet talents - uint8 level = getLevel(); - uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); - // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent) - if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel) - resetTalents(); // Remove all talent points - - SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount); - - if (!m_loading) - GetOwner()->SendTalentsInfoData(true); - */ -} - -uint8 Pet::GetMaxTalentPointsForLevel(uint8 level) const -{ - uint8 points = (level >= 20) ? ((level - 16) / 4) : 0; - // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS - points += GetOwner()->GetTotalAuraModifier(SPELL_AURA_MOD_PET_TALENT_POINTS); - return points; -} - void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply) { ASSERT(spellInfo); @@ -1940,3 +1790,96 @@ void Pet::ResetGroupUpdateFlag() if (GetOwner()->GetGroup()) GetOwner()->RemoveGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } + +void Pet::LearnSpecializationSpells() +{ + std::vector learnedSpells; + + if (std::vector const* specSpells = sDB2Manager.GetSpecializationSpells(m_petSpecialization)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID); + if (!spellInfo || spellInfo->SpellLevel > getLevel()) + continue; + + learnedSpells.push_back(specSpell->SpellID); + } + } + + learnSpells(learnedSpells); +} + +void Pet::RemoveSpecializationSpells(bool clearActionBar) +{ + std::vector unlearnedSpells; + + for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i) + { + if (ChrSpecializationEntry const* specialization = sChrSpecializationByIndexStore[0][i]) + { + if (std::vector const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + unlearnedSpells.push_back(specSpell->SpellID); + } + } + } + + if (ChrSpecializationEntry const* specialization = sChrSpecializationByIndexStore[PET_SPEC_OVERRIDE_CLASS_INDEX][i]) + { + if (std::vector const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID)) + { + for (size_t j = 0; j < specSpells->size(); ++j) + { + SpecializationSpellsEntry const* specSpell = specSpells->at(j); + unlearnedSpells.push_back(specSpell->SpellID); + } + } + } + } + + unlearnSpells(unlearnedSpells, true, clearActionBar); +} + +void Pet::SetSpecialization(uint16 spec) +{ + if (m_petSpecialization == spec) + return; + + // remove all the old spec's specalization spells, set the new spec, then add the new spec's spells + // clearActionBars is false because we'll be updating the pet actionbar later so we don't have to do it now + RemoveSpecializationSpells(false); + if (!sChrSpecializationStore.LookupEntry(spec)) + { + m_petSpecialization = 0; + return; + } + + m_petSpecialization = spec; + LearnSpecializationSpells(); + + // resend SMSG_PET_SPELLS_MESSAGE to remove old specialization spells from the pet action bar + CleanupActionBar(); + GetOwner()->PetSpellInitialize(); + + WorldPackets::Pet::SetPetSpecialization setPetSpecialization; + setPetSpecialization.SpecID = m_petSpecialization; + GetOwner()->GetSession()->SendPacket(setPetSpecialization.Write()); +} + +std::string Pet::GenerateActionBarData() const +{ + std::ostringstream ss; + + for (uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) + { + ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' ' + << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << ' '; + } + + return ss.str(); +} diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 170b881fa50..38d78ec181b 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -119,26 +119,24 @@ class TC_GAME_API Pet : public Guardian bool addSpell(uint32 spellId, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); bool learnSpell(uint32 spell_id); + void learnSpells(std::vector const& spellIds); void learnSpellHighRank(uint32 spellid); void InitLevelupSpellsForLevel(); bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + void unlearnSpells(std::vector const& spellIds, bool learn_prev, bool clear_ab = true); bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); void CleanupActionBar(); + std::string GenerateActionBarData() const; PetSpellMap m_spells; AutoSpellList m_autospells; void InitPetCreateSpells(); - bool resetTalents(); - static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = nullptr); - void InitTalentForLevel(); - - uint8 GetMaxTalentPointsForLevel(uint8 level) const; - uint8 GetFreeTalentPoints() const { return GetByteValue(UNIT_FIELD_BYTES_1, 1); } - void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); } - - uint32 m_usedTalentCount; + uint16 GetSpecialization() { return m_petSpecialization; } + void SetSpecialization(uint16 spec); + void LearnSpecializationSpells(); + void RemoveSpecializationSpells(bool clearActionBar); uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } void SetGroupUpdateFlag(uint32 flag); @@ -159,6 +157,8 @@ class TC_GAME_API Pet : public Guardian DeclinedName *m_declinedname; + uint16 m_petSpecialization; + private: void SaveToDB(uint32, uint32, uint32) override // override of Creature::SaveToDB - must not be called { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1efc4988a08..da964ef691f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -20162,7 +20162,7 @@ void Player::PetSpellInitialize() WorldPackets::Pet::PetSpells petSpellsPacket; petSpellsPacket.PetGUID = pet->GetGUID(); petSpellsPacket._CreatureFamily = pet->GetCreatureTemplate()->family; // creature family (required for pet talents) - //petSpellsPacket.Specialization = pet->GetSpecialization(); NYI + petSpellsPacket.Specialization = pet->GetSpecialization(); petSpellsPacket.TimeLimit = pet->GetDuration(); petSpellsPacket.ReactState = pet->GetReactState(); petSpellsPacket.CommandState = charmInfo->GetCommandState(); @@ -25954,7 +25954,6 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy { case SUMMON_PET: pet->InitPetCreateSpells(); - pet->InitTalentForLevel(); pet->SavePetToDB(PET_SAVE_AS_CURRENT); PetSpellInitialize(); break; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ee75a4ed58c..95a1317b17c 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1077,7 +1077,17 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) // reset for all pets before pet loading if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - Pet::resetTalentsForAllPetsOf(pCurrChar); + { + // Delete all of the player's pet spells + PreparedStatement* stmtSpells = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER); + stmtSpells->setUInt64(0, pCurrChar->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmtSpells); + + // Then reset all of the player's pet specualizations + PreparedStatement* stmtSpec = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER); + stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmtSpec); + } // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) pCurrChar->LoadPet(); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index a1e57ff087a..849a5097c61 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -722,3 +722,37 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec SendPacket(petNameInvalid.Write()); } + +void WorldSession::HandlePetSetSpecializationOpcode(WorldPackets::Pet::LearnPetSpecializationGroup& learnPetSpecializationGroup) +{ + if (!_player->IsInWorld()) + return; + + Pet* pet = ObjectAccessor::GetPet(*_player, learnPetSpecializationGroup.PetGUID); + + if (!pet || !pet->IsPet() || ((Pet*)pet)->getPetType() != HUNTER_PET || + pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) + return; + + if (learnPetSpecializationGroup.SpecGroupIndex >= MAX_SPECIALIZATIONS) + { + TC_LOG_DEBUG("network", "WORLD: HandlePetSetSpecializationOpcode - specialization index %u out of range", learnPetSpecializationGroup.SpecGroupIndex); + return; + } + + uint32 specIndex = _player->HasAuraType(SPELL_AURA_OVERRIDE_PET_SPECS) ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0; + ChrSpecializationEntry const* petSpec = sChrSpecializationByIndexStore[specIndex][learnPetSpecializationGroup.SpecGroupIndex]; + if (!petSpec) + { + TC_LOG_DEBUG("network", "WORLD: HandlePetSetSpecializationOpcode - specialization index %u not found", learnPetSpecializationGroup.SpecGroupIndex); + return; + } + + if (_player->getLevel() < MIN_SPECIALIZATION_LEVEL) + { + TC_LOG_DEBUG("network", "WORLD: HandlePetSetSpecializationOpcode - player level too low for specializations"); + return; + } + + pet->SetSpecialization(petSpec->ID); +} diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index b07a74dfb10..36a71ba9c53 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -185,3 +185,16 @@ void WorldPackets::Pet::PetCancelAura::Read() _worldPacket >> PetGUID; _worldPacket >> SpellID; } + +void WorldPackets::Pet::LearnPetSpecializationGroup::Read() +{ + _worldPacket >> PetGUID; + _worldPacket >> SpecGroupIndex; +} + +WorldPacket const* WorldPackets::Pet::SetPetSpecialization::Write() +{ + _worldPacket << uint16(SpecID); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 500fef3a249..f11a71a936c 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -226,6 +226,27 @@ namespace WorldPackets int32 SpellID = 0; }; + class LearnPetSpecializationGroup final : public ClientPacket + { + public: + LearnPetSpecializationGroup(WorldPacket&& packet) : ClientPacket(CMSG_LEARN_PET_SPECIALIZATION_GROUP, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGUID; + uint32 SpecGroupIndex = 0; + }; + + class SetPetSpecialization final : public ServerPacket + { + public: + SetPetSpecialization() : ServerPacket(SMSG_SET_PET_SPECIALIZATION, 2) { } + + WorldPacket const* Write() override; + + uint16 SpecID = 0; + }; + } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 44d05585373..c69d3613ada 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -430,7 +430,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_JOIN_RATED_BATTLEGROUND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_KEEP_ALIVE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_KEYBOUND_OVERRIDE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_LEARN_PET_SPECIALIZATION_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_LEARN_PET_SPECIALIZATION_GROUP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Pet::LearnPetSpecializationGroup, &WorldSession::HandlePetSetSpecializationOpcode); DEFINE_HANDLER(CMSG_LEARN_TALENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::LearnTalents, &WorldSession::HandleLearnTalentsOpcode); DEFINE_HANDLER(CMSG_LEAVE_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::LeaveGroup, &WorldSession::HandleLeaveGroupOpcode); DEFINE_HANDLER(CMSG_LEAVE_PET_BATTLE_QUEUE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -1586,7 +1586,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MELEE_ANIM_KIT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MOVEMENT_ANIM_KIT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PET_SPECIALIZATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PET_SPECIALIZATION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 3d661e1a8ff..b65a8b30d56 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -506,6 +506,7 @@ namespace WorldPackets class PetAction; class PetCancelAura; class PetSetAction; + class LearnPetSpecializationGroup; } namespace Petition @@ -1516,6 +1517,7 @@ class TC_GAME_API WorldSession void HandlePetCancelAuraOpcode(WorldPackets::Spells::PetCancelAura& packet); void HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutocast& packet); void HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell); + void HandlePetSetSpecializationOpcode(WorldPackets::Pet::LearnPetSpecializationGroup& learnPetSpecializationGroup); void HandleSetActionBarToggles(WorldPackets::Character::SetActionBarToggles& packet); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 911db589f2d..d866691bda5 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -204,7 +204,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT &AuraEffect::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE &AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes - &AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS + &AuraEffect::HandleNULL, //145 used by 5 spells in 6.2.4 dbc but the meaning of this aura changed (it's used by mind control spells but isn't the control itself) &AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK &AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS @@ -510,7 +510,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //448 &AuraEffect::HandleNULL, //449 &AuraEffect::HandleNULL, //450 - &AuraEffect::HandleNULL, //451 SPELL_AURA_OVERRIDE_PET_SPECS + &AuraEffect::HandleOverridePetSpecs, //451 SPELL_AURA_OVERRIDE_PET_SPECS &AuraEffect::HandleNULL, //452 &AuraEffect::HandleNoImmediateEffect, //453 SPELL_AURA_CHARGE_RECOVERY_MOD implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //454 SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER implemented in SpellHistory::GetChargeRecoveryTime @@ -2601,21 +2601,6 @@ void AuraEffect::HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode /*** SKILLS & TALENTS ***/ /****************************/ -void AuraEffect::HandleAuraModPetTalentsPoints(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // Recalculate pet talent points - if (Pet* pet = target->ToPlayer()->GetPet()) - pet->InitTalentForLevel(); -} - void AuraEffect::HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_SKILL))) @@ -6666,3 +6651,26 @@ void AuraEffect::HandleModSpellCategoryCooldown(AuraApplication const* aurApp, u if (Player* player = aurApp->GetTarget()->ToPlayer()) player->SendSpellCategoryCooldowns(); } + +void AuraEffect::HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Player* player = aurApp->GetTarget()->ToPlayer(); + if (!player) + return; + + if (player->getClass() != CLASS_HUNTER) + return; + + Pet* pet = player->GetPet(); + if (!pet) + return; + + ChrSpecializationEntry const* currSpec = sChrSpecializationStore.LookupEntry(pet->GetSpecialization()); + if (!currSpec) + return; + + pet->SetSpecialization(sChrSpecializationByIndexStore[apply ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0][currSpec->OrderIndex]->ID); +} diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 0d907e4148c..512852a39ec 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -174,7 +174,6 @@ class TC_GAME_API AuraEffect void HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode, bool apply) const; // skills & talents - void HandleAuraModPetTalentsPoints(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, bool apply) const; // movement void HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -305,6 +304,7 @@ class TC_GAME_API AuraEffect void HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const; // aura effect periodic tick handlers void HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 58f1f24e584..b72c03dc08a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2724,8 +2724,6 @@ void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/) // caster have pet now m_caster->SetMinion(pet, true); - pet->InitTalentForLevel(); - if (m_caster->GetTypeId() == TYPEID_PLAYER) { pet->SavePetToDB(PET_SAVE_AS_CURRENT); @@ -5265,8 +5263,6 @@ void Spell::EffectCreateTamedPet(SpellEffIndex /*effIndex*/) // unitTarget has pet now unitTarget->SetMinion(pet, true); - pet->InitTalentForLevel(); - if (unitTarget->GetTypeId() == TYPEID_PLAYER) { pet->SavePetToDB(PET_SAVE_AS_CURRENT); -- cgit v1.2.3 From 5776a256b8eae7125e7eba229709b2872b33304b Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 26 May 2016 23:13:31 +0200 Subject: Core/Pets: Fixed wrong prepared statement in bc1a81747ae032bc2ae3681d99f5f6058d20caff Thanks Lordron for pointing it out --- src/server/database/Database/Implementation/CharacterDatabase.cpp | 2 +- src/server/game/Handlers/CharacterHandler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 24f798f7f98..67aa54c5679 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -660,7 +660,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM `pet_spell` WHERE `guid` in (SELECT `id` FROM `character_pet` WHERE owner=?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM pet_spell WHERE guid in (SELECT id FROM character_pet WHERE owner=?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_PET_SPECS_BY_OWNER, "UPDATE character_pet SET specialization = 0 WHERE owner=?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 95a1317b17c..ee1d69571f0 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1084,7 +1084,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) CharacterDatabase.Execute(stmtSpells); // Then reset all of the player's pet specualizations - PreparedStatement* stmtSpec = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PET_SPELLS_BY_OWNER); + PreparedStatement* stmtSpec = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PET_SPECS_BY_OWNER); stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter()); CharacterDatabase.Execute(stmtSpec); } -- cgit v1.2.3 From d60fe0e5d55eeba9d8c422b7135e789f4af4b4b3 Mon Sep 17 00:00:00 2001 From: Golrag Date: Fri, 27 May 2016 15:17:51 +0200 Subject: Core/Battleground: Areatriggers will now check if player leaves the start area before the battleground begins in the following battlegrounds: (#15935) --- sql/updates/world/6.x/yyyy_mm_dd_xx.sql | 2 ++ src/server/game/Battlegrounds/Battleground.cpp | 6 ++++++ src/server/game/Battlegrounds/Battleground.h | 4 ++++ src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp | 13 ++++++++++--- src/server/game/Battlegrounds/Zones/BattlegroundAB.h | 7 +++++++ src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp | 13 ++++++++++--- src/server/game/Battlegrounds/Zones/BattlegroundAV.h | 7 +++++++ src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp | 15 ++++++++++----- src/server/game/Battlegrounds/Zones/BattlegroundEY.h | 7 +++++++ src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp | 12 +++++++++--- src/server/game/Battlegrounds/Zones/BattlegroundIC.h | 7 +++++++ src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp | 13 ++++++++++--- src/server/game/Battlegrounds/Zones/BattlegroundWS.h | 7 +++++++ src/server/game/Handlers/MiscHandler.cpp | 5 ++--- 14 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 sql/updates/world/6.x/yyyy_mm_dd_xx.sql (limited to 'src') diff --git a/sql/updates/world/6.x/yyyy_mm_dd_xx.sql b/sql/updates/world/6.x/yyyy_mm_dd_xx.sql new file mode 100644 index 00000000000..4d4230e5d72 --- /dev/null +++ b/sql/updates/world/6.x/yyyy_mm_dd_xx.sql @@ -0,0 +1,2 @@ +UPDATE `battleground_template` SET `MaxLvl`=100; +UPDATE `battleground_template` SET StartMaxDist=150 WHERE `ID`=1; -- Alterac Valley diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 0051f0698d9..68a61a28708 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1076,6 +1076,12 @@ void Battleground::StartBattleground() TC_LOG_DEBUG("bg.arena", "Arena match type: %u for Team1Id: %u - Team2Id: %u started.", m_ArenaType, m_ArenaTeamIds[TEAM_ALLIANCE], m_ArenaTeamIds[TEAM_HORDE]); } +void Battleground::TeleportPlayerToExploitLocation(Player* player) +{ + if (WorldSafeLocsEntry const* loc = GetExploitTeleportLocation(Team(player->GetBGTeam()))) + player->TeleportTo(loc->MapID, loc->Loc.X, loc->Loc.Y, loc->Loc.Z, loc->Facing); +} + void Battleground::AddPlayer(Player* player) { // remove afk from player diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 2ef7eca4aa1..4d2f5da1a24 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -438,6 +438,10 @@ class TC_GAME_API Battleground // Death related virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + virtual WorldSafeLocsEntry const* GetExploitTeleportLocation(Team /*team*/) { return nullptr; } + // GetExploitTeleportLocation(TeamId) must be implemented in the battleground subclass. + void TeleportPlayerToExploitLocation(Player* player); + virtual void AddPlayer(Player* player); // must be implemented in BG subclass void AddOrSetPlayerToCorrectBgGroup(Player* player, uint32 team); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 911fe259fc3..60e0a5f8db8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -231,11 +231,13 @@ void BattlegroundAB::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint3 void BattlegroundAB::HandleAreaTrigger(Player* player, uint32 trigger, bool entered) { - if (GetStatus() != STATUS_IN_PROGRESS) - return; - switch (trigger) { + case 6635: // Horde Start + case 6634: // Alliance Start + if (GetStatus() == STATUS_WAIT_JOIN && !entered) + TeleportPlayerToExploitLocation(player); + break; case 3948: // Arathi Basin Alliance Exit. if (player->GetTeam() != ALLIANCE) player->GetSession()->SendNotification("Only The Alliance can use that portal"); @@ -690,6 +692,11 @@ WorldSafeLocsEntry const* BattlegroundAB::GetClosestGraveYard(Player* player) return good_entry; } +WorldSafeLocsEntry const* BattlegroundAB::GetExploitTeleportLocation(Team team) +{ + return sWorldSafeLocsStore.LookupEntry(team == ALLIANCE ? AB_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : AB_EXPLOIT_TELEPORT_LOCATION_HORDE); +} + bool BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) { if (!Battleground::UpdatePlayerScore(player, type, value, doAddHonor)) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index e4bdf2f16d6..c452ca6fa2f 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -179,6 +179,12 @@ enum BG_AB_Objectives AB_OBJECTIVE_DEFEND_BASE = 123 }; +enum BG_AB_ExploitTeleportLocations +{ + AB_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3705, + AB_EXPLOIT_TELEPORT_LOCATION_HORDE = 3706 +}; + #define BG_AB_NotABBGWeekendHonorTicks 260 #define BG_AB_ABBGWeekendHonorTicks 160 #define BG_AB_NotABBGWeekendReputationTicks 160 @@ -288,6 +294,7 @@ class BattlegroundAB : public Battleground void Reset() override; void EndBattleground(uint32 winner) override; WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override; + WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override; /* Scorekeeping */ bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true) override; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 59d01df8237..031228013ef 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -493,11 +493,13 @@ void BattlegroundAV::RemovePlayer(Player* player, ObjectGuid /*guid*/, uint32 /* void BattlegroundAV::HandleAreaTrigger(Player* player, uint32 trigger, bool entered) { - if (GetStatus() != STATUS_IN_PROGRESS) - return; - switch (trigger) { + case 6633: // Horde Start + case 6632: // Alliance Start + if (GetStatus() == STATUS_WAIT_JOIN && entered) + TeleportPlayerToExploitLocation(player); + break; case 95: case 2608: if (player->GetTeam() != ALLIANCE) @@ -1124,6 +1126,11 @@ WorldSafeLocsEntry const* BattlegroundAV::GetClosestGraveYard(Player* player) return pGraveyard; } +WorldSafeLocsEntry const* BattlegroundAV::GetExploitTeleportLocation(Team team) +{ + return sWorldSafeLocsStore.LookupEntry(team == ALLIANCE ? AV_EXPLOIT_TELEPORT_LOCATION_ALLIANCE: AV_EXPLOIT_TELEPORT_LOCATION_HORDE); +} + bool BattlegroundAV::SetupBattleground() { // Create starting objects diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 8bf97822426..eae03d83bc1 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1536,6 +1536,12 @@ enum Texts TEXT_SNIVVLE_RANDOM = 0 }; +enum BG_AV_ExploitTeleportLocations +{ + AV_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3664, + AV_EXPLOIT_TELEPORT_LOCATION_HORDE = 3665 +}; + struct BG_AV_NodeInfo { BG_AV_States State; @@ -1633,6 +1639,7 @@ class BattlegroundAV : public Battleground void EndBattleground(uint32 winner) override; WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override; + WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override; // Achievement: Av perfection and Everything counts bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* source, Unit const* target = nullptr, uint32 miscvalue1 = 0) override; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 461420fe962..8bcba2ca204 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -406,14 +406,16 @@ void BattlegroundEY::RemovePlayer(Player* player, ObjectGuid guid, uint32 /*team void BattlegroundEY::HandleAreaTrigger(Player* player, uint32 trigger, bool entered) { - if (GetStatus() != STATUS_IN_PROGRESS) - return; - if (!player->IsAlive()) //hack code, must be removed later return; switch (trigger) { + case 4530: // Horde Start + case 4531: // Alliance Start + if (GetStatus() == STATUS_WAIT_JOIN && !entered) + TeleportPlayerToExploitLocation(player); + break; case TR_BLOOD_ELF_POINT: if (m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == player->GetTeam()) if (m_FlagState && GetFlagPickerGUID() == player->GetGUID()) @@ -438,8 +440,6 @@ void BattlegroundEY::HandleAreaTrigger(Player* player, uint32 trigger, bool ente case 4515: case 4517: case 4519: - case 4530: - case 4531: case 4568: case 4569: case 4570: @@ -950,6 +950,11 @@ WorldSafeLocsEntry const* BattlegroundEY::GetClosestGraveYard(Player* player) return nearestEntry; } +WorldSafeLocsEntry const* BattlegroundEY::GetExploitTeleportLocation(Team team) +{ + return sWorldSafeLocsStore.LookupEntry(team == ALLIANCE ? EY_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : EY_EXPLOIT_TELEPORT_LOCATION_HORDE); +} + bool BattlegroundEY::IsAllNodesControlledByTeam(uint32 team) const { uint32 count = 0; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index e25601f51b9..a1e63e356b8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -248,6 +248,12 @@ enum BG_EY_Objectives EY_OBJECTIVE_CAPTURE_FLAG = 183 }; +enum BG_EY_ExploitTeleportLocations +{ + EY_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3773, + EY_EXPLOIT_TELEPORT_LOCATION_HORDE = 3772 +}; + struct BattlegroundEYPointIconsStruct { BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex) @@ -376,6 +382,7 @@ class BattlegroundEY : public Battleground void HandleAreaTrigger(Player* source, uint32 trigger, bool entered) override; void HandleKillPlayer(Player* player, Player* killer) override; WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override; + WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override; bool SetupBattleground() override; void Reset() override; void UpdateTeamScore(uint32 Team); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index d31fd47819f..085da3d6b5a 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -263,11 +263,12 @@ void BattlegroundIC::RemovePlayer(Player* player, ObjectGuid /*guid*/, uint32 /* } } -void BattlegroundIC::HandleAreaTrigger(Player* player, uint32 trigger, bool /*entered*/) +void BattlegroundIC::HandleAreaTrigger(Player* player, uint32 trigger, bool entered) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; + if (GetStatus() == STATUS_WAIT_JOIN && !entered) + if (trigger == 9176 || trigger == 9178) + TeleportPlayerToExploitLocation(player); /// @hack: this spell should be cast by npc 22515 (World Trigger) and not by the player if (trigger == 5555 && player->GetTeamId() == TEAM_HORDE) @@ -884,6 +885,11 @@ WorldSafeLocsEntry const* BattlegroundIC::GetClosestGraveYard(Player* player) return good_entry; } +WorldSafeLocsEntry const * BattlegroundIC::GetExploitTeleportLocation(Team team) +{ + return sWorldSafeLocsStore.LookupEntry(team == ALLIANCE ? IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : IC_EXPLOIT_TELEPORT_LOCATION_HORDE); +} + bool BattlegroundIC::IsAllNodesControlledByTeam(uint32 team) const { uint32 count = 0; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index f60d9324e48..d65b69e62f4 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -468,6 +468,12 @@ enum BG_IC_MaxSpawns MAX_CAPTAIN_SPAWNS_PER_FACTION = 2, }; +enum BG_IC_ExploitTeleportLocations +{ + IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3986, + IC_EXPLOIT_TELEPORT_LOCATION_HORDE = 3983 +}; + const ICNpc BG_IC_NpcSpawnlocs[MAX_NORMAL_NPCS_SPAWNS] = { {BG_IC_NPC_OVERLORD_AGMAR, NPC_OVERLORD_AGMAR, TEAM_HORDE, 1295.44f, -765.733f, 70.0541f, 0.0f}, //Overlord Agmar 1 @@ -940,6 +946,7 @@ class BattlegroundIC : public Battleground void DestroyGate(Player* player, GameObject* go) override; WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override; + WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override; /* Scorekeeping */ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 0df4fd6f88e..37b39043e42 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -650,13 +650,15 @@ void BattlegroundWS::UpdateTeamScore(uint32 team) void BattlegroundWS::HandleAreaTrigger(Player* player, uint32 trigger, bool entered) { - if (GetStatus() != STATUS_IN_PROGRESS) - return; - //uint32 SpellId = 0; //uint64 buff_guid = 0; switch (trigger) { + case 8965: // Horde Start + case 8966: // Alliance Start + if (GetStatus() == STATUS_WAIT_JOIN && !entered) + TeleportPlayerToExploitLocation(player); + break; case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in Battleground::Update(). //buff_guid = BgObjects[BG_WS_OBJECT_SPEEDBUFF_1]; break; @@ -851,6 +853,11 @@ WorldSafeLocsEntry const* BattlegroundWS::GetClosestGraveYard(Player* player) } } +WorldSafeLocsEntry const* BattlegroundWS::GetExploitTeleportLocation(Team team) +{ + return sWorldSafeLocsStore.LookupEntry(team == ALLIANCE ? WS_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : WS_EXPLOIT_TELEPORT_LOCATION_HORDE); +} + void BattlegroundWS::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) { packet.Worldstates.emplace_back(uint32(BG_WS_FLAG_CAPTURES_ALLIANCE), int32(GetTeamScore(TEAM_ALLIANCE))); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index 3561d6f2fc3..8731255cd32 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -125,6 +125,12 @@ enum BG_WS_Graveyards WS_GRAVEYARD_MAIN_HORDE = 772 }; +enum BG_WS_ExploitTeleportLocations +{ + WS_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3784, + WS_EXPLOIT_TELEPORT_LOCATION_HORDE = 3785 +}; + enum BG_WS_CreatureTypes { WS_SPIRIT_MAIN_ALLIANCE = 0, @@ -222,6 +228,7 @@ class BattlegroundWS : public Battleground void Reset() override; void EndBattleground(uint32 winner) override; WorldSafeLocsEntry const* GetClosestGraveYard(Player* player) override; + WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override; void UpdateFlagState(uint32 team, uint32 value); void SetLastFlagCapture(uint32 team) { _lastFlagCaptureTeam = team; } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index a43ec6c2202..382b8d70f38 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -485,7 +485,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::Misc::AreaTrigger& pack return; } - if (!player->IsInAreaTriggerRadius(atEntry)) + if (packet.Entered && !player->IsInAreaTriggerRadius(atEntry)) { TC_LOG_DEBUG("network", "HandleAreaTriggerOpcode: Player '%s' (%s) too far, ignore Area Trigger ID: %u", player->GetName().c_str(), player->GetGUID().ToString().c_str(), packet.AreaTriggerID); @@ -535,8 +535,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::Misc::AreaTrigger& pack } if (Battleground* bg = player->GetBattleground()) - if (bg->GetStatus() == STATUS_IN_PROGRESS) - bg->HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered); + bg->HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered); if (OutdoorPvP* pvp = player->GetOutdoorPvP()) if (pvp->HandleAreaTrigger(_player, packet.AreaTriggerID, packet.Entered)) -- cgit v1.2.3 From cd51e27e195c67bc9f2e3a38c1e5e8a5a243e6bf Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 28 May 2016 11:33:06 +0200 Subject: Core/Auras: Implemented aura 475 - SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED --- src/server/game/Spells/Auras/SpellAuraDefines.h | 2 +- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 16 +++++++++++++++- src/server/game/Spells/Auras/SpellAuraEffects.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index d781a8822b8..3663843868a 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -531,7 +531,7 @@ enum AuraType SPELL_AURA_472 = 472, SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT = 473, // Prevents durability loss from dealing/taking damage SPELL_AURA_474 = 474, - SPELL_AURA_475 = 475, + SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED = 475, SPELL_AURA_476 = 476, SPELL_AURA_477 = 477, SPELL_AURA_478 = 478, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index d866691bda5..a5926e8f85c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -534,7 +534,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //472 &AuraEffect::HandleNoImmediateEffect, //473 SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT implemented in Player::DurabilityPointLossForEquipSlot &AuraEffect::HandleNULL, //474 - &AuraEffect::HandleNULL, //475 + &AuraEffect::HandleAllowUsingGameobjectsWhileMounted, //475 SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED &AuraEffect::HandleNULL, //476 &AuraEffect::HandleNULL, //477 &AuraEffect::HandleNULL, //478 @@ -6674,3 +6674,17 @@ void AuraEffect::HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mod pet->SetSpecialization(sChrSpecializationByIndexStore[apply ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0][currSpec->OrderIndex]->ID); } + +void AuraEffect::HandleAllowUsingGameobjectsWhileMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + if (aurApp->GetTarget()->GetTypeId() != TYPEID_PLAYER) + return; + + if (apply) + aurApp->GetTarget()->SetFlag(PLAYER_FIELD_LOCAL_FLAGS, PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED); + else if (!aurApp->GetTarget()->HasAuraType(SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED)) + aurApp->GetTarget()->RemoveFlag(PLAYER_FIELD_LOCAL_FLAGS, PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED); +} diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 512852a39ec..39b1cdf3eb8 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -305,6 +305,7 @@ class TC_GAME_API AuraEffect void HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAllowUsingGameobjectsWhileMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const; // aura effect periodic tick handlers void HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const; -- cgit v1.2.3 From 186375d997caab33eee878a1e102f41939c7a688 Mon Sep 17 00:00:00 2001 From: Trond B Krokli Date: Sun, 29 May 2016 16:06:07 +0200 Subject: Core/DB/Updater: English grammar corrections (#17207) Improve English text in strings and comments in UpdateFetcher.cpp - replace incorrect text with the intended words in some output strings - corrections in the comments to point out the intention of the code --- src/server/database/Updater/UpdateFetcher.cpp | 46 +++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index 7dc0a307ca2..3d81b9e035e 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -67,11 +67,11 @@ void UpdateFetcher::FillFileListRecursively(Path const& path, LocaleFileStorage& LocaleFileEntry const entry = { itr->path(), state }; // Check for doubled filenames - // Since elements are only compared through their filenames this is ok + // Because elements are only compared by their filenames, this is ok if (storage.find(entry) != storage.end()) { - TC_LOG_FATAL("sql.updates", "Duplicated filename occurred \"%s\", since updates are ordered " \ - "through its filename every name needs to be unique!", itr->path().generic_string().c_str()); + TC_LOG_FATAL("sql.updates", "Duplicate filename \"%s\" occurred. Because updates are ordered " \ + "by their filenames, every name needs to be unique!", itr->path().generic_string().c_str()); throw UpdateException("Updating failed, see the log for details."); } @@ -101,7 +101,7 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons if (!is_directory(p)) { - TC_LOG_WARN("sql.updates", "DBUpdater: Given update include directory \"%s\" isn't existing, skipped!", p.generic_string().c_str()); + TC_LOG_WARN("sql.updates", "DBUpdater: Given update include directory \"%s\" does not exist, skipped!", p.generic_string().c_str()); continue; } @@ -144,7 +144,7 @@ std::string UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) co { TC_LOG_FATAL("sql.updates", "Failed to open the sql update \"%s\" for reading! " "Stopping the server to keep the database integrity, " - "try to identify and solve the issue or disabled the database updater.", + "try to identify and solve the issue or disable the database updater.", file.generic_string().c_str()); throw UpdateException("Opening the sql update failed!"); @@ -192,7 +192,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, AppliedFileStorage::const_iterator iter = applied.find(availableQuery.first.filename().string()); if (iter != applied.end()) { - // If redundancy is disabled skip it since the update is already applied. + // If redundancy is disabled, skip it, because the update is already applied. if (!redundancyChecks) { TC_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks."); @@ -200,7 +200,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, continue; } - // If the update is in an archived directory and is marked as archived in our database skip redundancy checks (archived updates never change). + // If the update is in an archived directory and is marked as archived in our database, skip redundancy checks (archived updates never change). if (!archivedRedundancy && (iter->second.state == ARCHIVED) && (availableQuery.second == ARCHIVED)) { TC_LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks."); @@ -217,11 +217,11 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, // Update is not in our applied list if (iter == applied.end()) { - // Catch renames (different filename but same hash) + // Catch renames (different filename, but same hash) HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash); if (hashIter != hashToName.end()) { - // Check if the original file was removed if not we've got a problem. + // Check if the original file was removed. If not, we've got a problem. LocaleFileStorage::const_iterator localeIter; // Push localeIter forward for (localeIter = available.begin(); (localeIter != available.end()) && @@ -230,12 +230,12 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, // Conflict! if (localeIter != available.end()) { - TC_LOG_WARN("sql.updates", ">> Seems like update \"%s\" \'%s\' was renamed, but the old file is still there! " \ - "Trade it as a new file! (Probably its an unmodified copy of file \"%s\")", + TC_LOG_WARN("sql.updates", ">> It seems like the update \"%s\" \'%s\' was renamed, but the old file is still there! " \ + "Treating it as a new file! (It is probably an unmodified copy of the file \"%s\")", availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str(), localeIter->first.filename().string().c_str()); } - // Its save to trade the file as renamed here + // It is safe to treat the file as renamed here else { TC_LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.", @@ -253,7 +253,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str()); } } - // Rehash the update entry if it is contained in our database but with an empty hash. + // Rehash the update entry if it exists in our database with an empty hash. else if (allowRehash && iter->second.hash.empty()) { mode = MODE_REHASH; @@ -263,7 +263,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, } else { - // If the hash of the files differs from the one stored in our database reapply the update (because it was changed). + // If the hash of the files differs from the one stored in our database, reapply the update (because it changed). if (iter->second.hash != hash) { TC_LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", availableQuery.first.filename().string().c_str(), @@ -271,16 +271,16 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, } else { - // If the file wasn't changed and just moved update its state if necessary. + // If the file wasn't changed and just moved, update its state (if necessary). if (iter->second.state != availableQuery.second) { - TC_LOG_DEBUG("sql.updates", ">> Updating state of \"%s\" to \'%s\'...", + TC_LOG_DEBUG("sql.updates", ">> Updating the state of \"%s\" to \'%s\'...", availableQuery.first.filename().string().c_str(), AppliedFileEntry::StateConvert(availableQuery.second).c_str()); UpdateState(availableQuery.first.filename().string(), availableQuery.second); } - TC_LOG_DEBUG("sql.updates", ">> Update is already applied and is matching hash \'%s\'.", hash.substr(0, 7).c_str()); + TC_LOG_DEBUG("sql.updates", ">> Update is already applied and matches the hash \'%s\'.", hash.substr(0, 7).c_str()); applied.erase(iter); continue; @@ -307,14 +307,14 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, ++importedUpdates; } - // Cleanup up orphaned entries if enabled + // Cleanup up orphaned entries (if enabled) if (!applied.empty()) { bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast(cleanDeadReferencesMaxCount)); for (auto const& entry : applied) { - TC_LOG_WARN("sql.updates", ">> File \'%s\' was applied to the database but is missing in" \ + TC_LOG_WARN("sql.updates", ">> The file \'%s\' was applied to the database, but is missing in" \ " your update directory now!", entry.first.c_str()); if (doCleanup) @@ -325,8 +325,8 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, CleanUp(applied); else { - TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There are " SZFMTD " dirty files that were applied to your database " \ - "but are now missing in your source directory!", applied.size()); + TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There were " SZFMTD " dirty files applied to your database, " \ + "but they are now missing in your source directory!", applied.size()); } } @@ -343,7 +343,7 @@ uint32 UpdateFetcher::Apply(Path const& path) const // Update database _applyFile(path); - // Return time the query took to apply + // Return the time it took the query to apply return uint32(std::chrono::duration_cast(Time::now() - begin).count()); } @@ -358,7 +358,7 @@ void UpdateFetcher::UpdateEntry(AppliedFileEntry const& entry, uint32 const spee void UpdateFetcher::RenameEntry(std::string const& from, std::string const& to) const { - // Delete target if it exists + // Delete the target if it exists { std::string const update = "DELETE FROM `updates` WHERE `name`=\"" + to + "\""; -- cgit v1.2.3 From 529e072fa34e3b7f73fb1783124ae50488d762c2 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 29 May 2016 19:05:45 +0200 Subject: Core/Spells: Defined new spell attribute (SPELL_ATTR12_IS_GARRISON_BUFF) --- src/server/game/Miscellaneous/SharedDefines.h | 240 +++++++++++++------------- 1 file changed, 120 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 63079904a67..e9f6c3f3aff 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -713,138 +713,138 @@ enum SpellAttr9 enum SpellAttr10 { - SPELL_ATTR10_UNK0 = 0x00000001, // 0 - SPELL_ATTR10_UNK1 = 0x00000002, // 1 - SPELL_ATTR10_UNK2 = 0x00000004, // 2 - SPELL_ATTR10_UNK3 = 0x00000008, // 3 - SPELL_ATTR10_WATER_SPOUT = 0x00000010, // 4 - SPELL_ATTR10_UNK5 = 0x00000020, // 5 - SPELL_ATTR10_UNK6 = 0x00000040, // 6 - SPELL_ATTR10_TELEPORT_PLAYER = 0x00000080, // 7 4 Teleport Player spells - SPELL_ATTR10_UNK8 = 0x00000100, // 8 - SPELL_ATTR10_UNK9 = 0x00000200, // 9 - SPELL_ATTR10_UNK10 = 0x00000400, // 10 - SPELL_ATTR10_HERB_GATHERING_MINING = 0x00000800, // 11 Only Herb Gathering and Mining - SPELL_ATTR10_UNK12 = 0x00001000, // 12 - SPELL_ATTR10_UNK13 = 0x00002000, // 13 - SPELL_ATTR10_UNK14 = 0x00004000, // 14 - SPELL_ATTR10_UNK15 = 0x00008000, // 15 - SPELL_ATTR10_UNK16 = 0x00010000, // 16 - SPELL_ATTR10_UNK17 = 0x00020000, // 17 - SPELL_ATTR10_UNK18 = 0x00040000, // 18 - SPELL_ATTR10_UNK19 = 0x00080000, // 19 - SPELL_ATTR10_UNK20 = 0x00100000, // 20 - SPELL_ATTR10_UNK21 = 0x00200000, // 21 - SPELL_ATTR10_UNK22 = 0x00400000, // 22 - SPELL_ATTR10_UNK23 = 0x00800000, // 23 - SPELL_ATTR10_UNK24 = 0x01000000, // 24 - SPELL_ATTR10_UNK25 = 0x02000000, // 25 - SPELL_ATTR10_UNK26 = 0x04000000, // 26 - SPELL_ATTR10_UNK27 = 0x08000000, // 27 - SPELL_ATTR10_UNK28 = 0x10000000, // 28 - SPELL_ATTR10_MOUNT_IS_NOT_ACCOUNT_WIDE = 0x20000000, // 29 This mount is stored per-character - SPELL_ATTR10_UNK30 = 0x40000000, // 30 - SPELL_ATTR10_UNK31 = 0x80000000 // 31 + SPELL_ATTR10_UNK0 = 0x00000001, // 0 + SPELL_ATTR10_UNK1 = 0x00000002, // 1 + SPELL_ATTR10_UNK2 = 0x00000004, // 2 + SPELL_ATTR10_UNK3 = 0x00000008, // 3 + SPELL_ATTR10_WATER_SPOUT = 0x00000010, // 4 + SPELL_ATTR10_UNK5 = 0x00000020, // 5 + SPELL_ATTR10_UNK6 = 0x00000040, // 6 + SPELL_ATTR10_TELEPORT_PLAYER = 0x00000080, // 7 4 Teleport Player spells + SPELL_ATTR10_UNK8 = 0x00000100, // 8 + SPELL_ATTR10_UNK9 = 0x00000200, // 9 + SPELL_ATTR10_UNK10 = 0x00000400, // 10 + SPELL_ATTR10_HERB_GATHERING_MINING = 0x00000800, // 11 Only Herb Gathering and Mining + SPELL_ATTR10_UNK12 = 0x00001000, // 12 + SPELL_ATTR10_UNK13 = 0x00002000, // 13 + SPELL_ATTR10_UNK14 = 0x00004000, // 14 + SPELL_ATTR10_UNK15 = 0x00008000, // 15 + SPELL_ATTR10_UNK16 = 0x00010000, // 16 + SPELL_ATTR10_UNK17 = 0x00020000, // 17 + SPELL_ATTR10_UNK18 = 0x00040000, // 18 + SPELL_ATTR10_UNK19 = 0x00080000, // 19 + SPELL_ATTR10_UNK20 = 0x00100000, // 20 + SPELL_ATTR10_UNK21 = 0x00200000, // 21 + SPELL_ATTR10_UNK22 = 0x00400000, // 22 + SPELL_ATTR10_UNK23 = 0x00800000, // 23 + SPELL_ATTR10_UNK24 = 0x01000000, // 24 + SPELL_ATTR10_UNK25 = 0x02000000, // 25 + SPELL_ATTR10_UNK26 = 0x04000000, // 26 + SPELL_ATTR10_UNK27 = 0x08000000, // 27 + SPELL_ATTR10_UNK28 = 0x10000000, // 28 + SPELL_ATTR10_MOUNT_IS_NOT_ACCOUNT_WIDE = 0x20000000, // 29 This mount is stored per-character + SPELL_ATTR10_UNK30 = 0x40000000, // 30 + SPELL_ATTR10_UNK31 = 0x80000000 // 31 }; enum SpellAttr11 { - SPELL_ATTR11_UNK0 = 0x00000001, // 0 - SPELL_ATTR11_UNK1 = 0x00000002, // 1 - SPELL_ATTR11_SCALES_WITH_ITEM_LEVEL = 0x00000004, // 2 - SPELL_ATTR11_UNK3 = 0x00000008, // 3 - SPELL_ATTR11_UNK4 = 0x00000010, // 4 - SPELL_ATTR11_UNK5 = 0x00000020, // 5 - SPELL_ATTR11_UNK6 = 0x00000040, // 6 - SPELL_ATTR11_NO_RANK = 0x00000080, // 7 Spell_C_GetSpellRank returns 0 instead of 5 * std::min(SpellLevels->MaxLevel, caster->Level) - SPELL_ATTR11_UNK8 = 0x00000100, // 8 - SPELL_ATTR11_UNK9 = 0x00000200, // 9 - SPELL_ATTR11_UNK10 = 0x00000400, // 10 - SPELL_ATTR11_UNK11 = 0x00000800, // 11 - SPELL_ATTR11_UNK12 = 0x00001000, // 12 - SPELL_ATTR11_UNK13 = 0x00002000, // 13 - SPELL_ATTR11_UNK14 = 0x00004000, // 14 - SPELL_ATTR11_UNK15 = 0x00008000, // 15 - SPELL_ATTR11_NOT_USABLE_IN_CHALLENGE_MODE = 0x00010000, // 16 - SPELL_ATTR11_UNK17 = 0x00020000, // 17 - SPELL_ATTR11_UNK18 = 0x00040000, // 18 - SPELL_ATTR11_UNK19 = 0x00080000, // 19 - SPELL_ATTR11_UNK20 = 0x00100000, // 20 - SPELL_ATTR11_UNK21 = 0x00200000, // 21 - SPELL_ATTR11_UNK22 = 0x00400000, // 22 - SPELL_ATTR11_UNK23 = 0x00800000, // 23 - SPELL_ATTR11_UNK24 = 0x01000000, // 24 - SPELL_ATTR11_UNK25 = 0x02000000, // 25 - SPELL_ATTR11_UNK26 = 0x04000000, // 26 - SPELL_ATTR11_UNK27 = 0x08000000, // 27 - SPELL_ATTR11_UNK28 = 0x10000000, // 28 - SPELL_ATTR11_UNK29 = 0x20000000, // 29 - SPELL_ATTR11_UNK30 = 0x40000000, // 30 - SPELL_ATTR11_UNK31 = 0x80000000 // 31 + SPELL_ATTR11_UNK0 = 0x00000001, // 0 + SPELL_ATTR11_UNK1 = 0x00000002, // 1 + SPELL_ATTR11_SCALES_WITH_ITEM_LEVEL = 0x00000004, // 2 + SPELL_ATTR11_UNK3 = 0x00000008, // 3 + SPELL_ATTR11_UNK4 = 0x00000010, // 4 + SPELL_ATTR11_UNK5 = 0x00000020, // 5 + SPELL_ATTR11_UNK6 = 0x00000040, // 6 + SPELL_ATTR11_NO_RANK = 0x00000080, // 7 Spell_C_GetSpellRank returns 0 instead of 5 * std::min(SpellLevels->MaxLevel, caster->Level) + SPELL_ATTR11_UNK8 = 0x00000100, // 8 + SPELL_ATTR11_UNK9 = 0x00000200, // 9 + SPELL_ATTR11_UNK10 = 0x00000400, // 10 + SPELL_ATTR11_UNK11 = 0x00000800, // 11 + SPELL_ATTR11_UNK12 = 0x00001000, // 12 + SPELL_ATTR11_UNK13 = 0x00002000, // 13 + SPELL_ATTR11_UNK14 = 0x00004000, // 14 + SPELL_ATTR11_UNK15 = 0x00008000, // 15 + SPELL_ATTR11_NOT_USABLE_IN_CHALLENGE_MODE = 0x00010000, // 16 + SPELL_ATTR11_UNK17 = 0x00020000, // 17 + SPELL_ATTR11_UNK18 = 0x00040000, // 18 + SPELL_ATTR11_UNK19 = 0x00080000, // 19 + SPELL_ATTR11_UNK20 = 0x00100000, // 20 + SPELL_ATTR11_UNK21 = 0x00200000, // 21 + SPELL_ATTR11_UNK22 = 0x00400000, // 22 + SPELL_ATTR11_UNK23 = 0x00800000, // 23 + SPELL_ATTR11_UNK24 = 0x01000000, // 24 + SPELL_ATTR11_UNK25 = 0x02000000, // 25 + SPELL_ATTR11_UNK26 = 0x04000000, // 26 + SPELL_ATTR11_UNK27 = 0x08000000, // 27 + SPELL_ATTR11_UNK28 = 0x10000000, // 28 + SPELL_ATTR11_UNK29 = 0x20000000, // 29 + SPELL_ATTR11_UNK30 = 0x40000000, // 30 + SPELL_ATTR11_UNK31 = 0x80000000 // 31 }; enum SpellAttr12 { - SPELL_ATTR12_UNK0 = 0x00000001, // 0 - SPELL_ATTR12_UNK1 = 0x00000002, // 1 - SPELL_ATTR12_UNK2 = 0x00000004, // 2 - SPELL_ATTR12_UNK3 = 0x00000008, // 3 - SPELL_ATTR12_UNK4 = 0x00000010, // 4 - SPELL_ATTR12_UNK5 = 0x00000020, // 5 - SPELL_ATTR12_UNK6 = 0x00000040, // 6 - SPELL_ATTR12_UNK7 = 0x00000080, // 7 - SPELL_ATTR12_UNK8 = 0x00000100, // 8 - SPELL_ATTR12_UNK9 = 0x00000200, // 9 - SPELL_ATTR12_UNK10 = 0x00000400, // 10 - SPELL_ATTR12_UNK11 = 0x00000800, // 11 - SPELL_ATTR12_UNK12 = 0x00001000, // 12 - SPELL_ATTR12_UNK13 = 0x00002000, // 13 - SPELL_ATTR12_UNK14 = 0x00004000, // 14 - SPELL_ATTR12_UNK15 = 0x00008000, // 15 - SPELL_ATTR12_UNK16 = 0x00010000, // 16 - SPELL_ATTR12_UNK17 = 0x00020000, // 17 - SPELL_ATTR12_UNK18 = 0x00040000, // 18 - SPELL_ATTR12_UNK19 = 0x00080000, // 19 - SPELL_ATTR12_UNK20 = 0x00100000, // 20 - SPELL_ATTR12_UNK21 = 0x00200000, // 21 - SPELL_ATTR12_UNK22 = 0x00400000, // 22 - SPELL_ATTR12_UNK23 = 0x00800000, // 23 - SPELL_ATTR12_UNK24 = 0x01000000, // 24 - SPELL_ATTR12_UNK25 = 0x02000000, // 25 - SPELL_ATTR12_UNK26 = 0x04000000, // 26 - SPELL_ATTR12_IS_READINESS_SPELL = 0x08000000, // 27 - SPELL_ATTR12_UNK28 = 0x10000000, // 28 - SPELL_ATTR12_UNK29 = 0x20000000, // 29 - SPELL_ATTR12_UNK30 = 0x40000000, // 30 - SPELL_ATTR12_UNK31 = 0x80000000 // 31 + SPELL_ATTR12_UNK0 = 0x00000001, // 0 + SPELL_ATTR12_UNK1 = 0x00000002, // 1 + SPELL_ATTR12_UNK2 = 0x00000004, // 2 + SPELL_ATTR12_UNK3 = 0x00000008, // 3 + SPELL_ATTR12_UNK4 = 0x00000010, // 4 + SPELL_ATTR12_UNK5 = 0x00000020, // 5 + SPELL_ATTR12_UNK6 = 0x00000040, // 6 + SPELL_ATTR12_UNK7 = 0x00000080, // 7 + SPELL_ATTR12_UNK8 = 0x00000100, // 8 + SPELL_ATTR12_UNK9 = 0x00000200, // 9 + SPELL_ATTR12_UNK10 = 0x00000400, // 10 + SPELL_ATTR12_UNK11 = 0x00000800, // 11 + SPELL_ATTR12_UNK12 = 0x00001000, // 12 + SPELL_ATTR12_UNK13 = 0x00002000, // 13 + SPELL_ATTR12_UNK14 = 0x00004000, // 14 + SPELL_ATTR12_UNK15 = 0x00008000, // 15 + SPELL_ATTR12_UNK16 = 0x00010000, // 16 + SPELL_ATTR12_UNK17 = 0x00020000, // 17 + SPELL_ATTR12_UNK18 = 0x00040000, // 18 + SPELL_ATTR12_UNK19 = 0x00080000, // 19 + SPELL_ATTR12_UNK20 = 0x00100000, // 20 + SPELL_ATTR12_UNK21 = 0x00200000, // 21 + SPELL_ATTR12_UNK22 = 0x00400000, // 22 + SPELL_ATTR12_UNK23 = 0x00800000, // 23 + SPELL_ATTR12_IS_GARRISON_BUFF = 0x01000000, // 24 + SPELL_ATTR12_UNK25 = 0x02000000, // 25 + SPELL_ATTR12_UNK26 = 0x04000000, // 26 + SPELL_ATTR12_IS_READINESS_SPELL = 0x08000000, // 27 + SPELL_ATTR12_UNK28 = 0x10000000, // 28 + SPELL_ATTR12_UNK29 = 0x20000000, // 29 + SPELL_ATTR12_UNK30 = 0x40000000, // 30 + SPELL_ATTR12_UNK31 = 0x80000000 // 31 }; enum SpellAttr13 { - SPELL_ATTR13_UNK0 = 0x00000001, // 0 - SPELL_ATTR13_UNK1 = 0x00000002, // 1 - SPELL_ATTR13_UNK2 = 0x00000004, // 2 - SPELL_ATTR13_UNK3 = 0x00000008, // 3 - SPELL_ATTR13_UNK4 = 0x00000010, // 4 - SPELL_ATTR13_UNK5 = 0x00000020, // 5 - SPELL_ATTR13_UNK6 = 0x00000040, // 6 - SPELL_ATTR13_UNK7 = 0x00000080, // 7 - SPELL_ATTR13_UNK8 = 0x00000100, // 8 - SPELL_ATTR13_UNK9 = 0x00000200, // 9 - SPELL_ATTR13_UNK10 = 0x00000400, // 10 - SPELL_ATTR13_UNK11 = 0x00000800, // 11 - SPELL_ATTR13_UNK12 = 0x00001000, // 12 - SPELL_ATTR13_UNK13 = 0x00002000, // 13 - SPELL_ATTR13_UNK14 = 0x00004000, // 14 - SPELL_ATTR13_UNK15 = 0x00008000, // 15 - SPELL_ATTR13_UNK16 = 0x00010000, // 16 - SPELL_ATTR13_UNK17 = 0x00020000, // 17 - SPELL_ATTR13_ACTIVATES_REQUIRED_SHAPESHIFT = 0x00040000, // 18 - SPELL_ATTR13_UNK19 = 0x00080000, // 19 - SPELL_ATTR13_UNK20 = 0x00100000, // 20 - SPELL_ATTR13_UNK21 = 0x00200000, // 21 - SPELL_ATTR13_UNK22 = 0x00400000, // 22 - SPELL_ATTR13_UNK23 = 0x00800000 // 23 + SPELL_ATTR13_UNK0 = 0x00000001, // 0 + SPELL_ATTR13_UNK1 = 0x00000002, // 1 + SPELL_ATTR13_UNK2 = 0x00000004, // 2 + SPELL_ATTR13_UNK3 = 0x00000008, // 3 + SPELL_ATTR13_UNK4 = 0x00000010, // 4 + SPELL_ATTR13_UNK5 = 0x00000020, // 5 + SPELL_ATTR13_UNK6 = 0x00000040, // 6 + SPELL_ATTR13_UNK7 = 0x00000080, // 7 + SPELL_ATTR13_UNK8 = 0x00000100, // 8 + SPELL_ATTR13_UNK9 = 0x00000200, // 9 + SPELL_ATTR13_UNK10 = 0x00000400, // 10 + SPELL_ATTR13_UNK11 = 0x00000800, // 11 + SPELL_ATTR13_UNK12 = 0x00001000, // 12 + SPELL_ATTR13_UNK13 = 0x00002000, // 13 + SPELL_ATTR13_UNK14 = 0x00004000, // 14 + SPELL_ATTR13_UNK15 = 0x00008000, // 15 + SPELL_ATTR13_UNK16 = 0x00010000, // 16 + SPELL_ATTR13_UNK17 = 0x00020000, // 17 + SPELL_ATTR13_ACTIVATES_REQUIRED_SHAPESHIFT = 0x00040000, // 18 + SPELL_ATTR13_UNK19 = 0x00080000, // 19 + SPELL_ATTR13_UNK20 = 0x00100000, // 20 + SPELL_ATTR13_UNK21 = 0x00200000, // 21 + SPELL_ATTR13_UNK22 = 0x00400000, // 22 + SPELL_ATTR13_UNK23 = 0x00800000 // 23 }; #define MIN_TALENT_GROUP 0 -- cgit v1.2.3 From fde9e8985f203048f07909bf0d3b0865cda55c42 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 30 May 2016 18:31:30 +0200 Subject: Core/Spells: Implemented auras 394 and 469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT (WITH_DIFFICULTY) --- src/server/game/Spells/Auras/SpellAuraDefines.h | 5 +++-- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 24 +++++++++++++++++++++-- src/server/game/Spells/Auras/SpellAuraEffects.h | 1 + src/server/game/Spells/Auras/SpellAuras.cpp | 4 ++++ 4 files changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 3663843868a..1d1de78b18b 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -451,7 +451,7 @@ enum AuraType SPELL_AURA_391 = 391, SPELL_AURA_392 = 392, SPELL_AURA_393 = 393, - SPELL_AURA_394 = 394, + SPELL_AURA_SHOW_CONFIRMATION_PROMPT = 394, SPELL_AURA_AREA_TRIGGER = 395, // NYI SPELL_AURA_396 = 396, SPELL_AURA_397 = 397, @@ -526,7 +526,8 @@ enum AuraType SPELL_AURA_MOD_BONUS_ARMOR_PCT = 466, // Affects bonus armor gain from all sources except base stats SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats SPELL_AURA_468 = 468, - SPELL_AURA_469 = 469, + SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY = 469, + SPELL_AURA_470 = 470, SPELL_AURA_471 = 471, SPELL_AURA_472 = 472, SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT = 473, // Prevents durability loss from dealing/taking damage diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a5926e8f85c..d3fc6c5e592 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -453,7 +453,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //391 &AuraEffect::HandleNULL, //392 &AuraEffect::HandleNULL, //393 - &AuraEffect::HandleNULL, //394 + &AuraEffect::HandleShowConfirmationPrompt, //394 SPELL_AURA_SHOW_CONFIRMATION_PROMPT &AuraEffect::HandleNULL, //395 SPELL_AURA_AREA_TRIGGER &AuraEffect::HandleNULL, //396 &AuraEffect::HandleNULL, //397 @@ -528,7 +528,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //466 SPELL_AURA_MOD_BONUS_ARMOR_PCT &AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT &AuraEffect::HandleNULL, //468 - &AuraEffect::HandleNULL, //469 + &AuraEffect::HandleShowConfirmationPrompt, //469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY &AuraEffect::HandleNULL, //470 &AuraEffect::HandleNULL, //471 &AuraEffect::HandleNULL, //472 @@ -706,6 +706,11 @@ int32 AuraEffect::CalculateAmount(Unit* caster) break; } } + case SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY: + if (caster) + amount = caster->GetMap()->GetDifficultyID(); + m_canBeRecalculated = false; + break; default: break; } @@ -6652,6 +6657,21 @@ void AuraEffect::HandleModSpellCategoryCooldown(AuraApplication const* aurApp, u player->SendSpellCategoryCooldowns(); } +void AuraEffect::HandleShowConfirmationPrompt(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Player* player = aurApp->GetTarget()->ToPlayer(); + if (!player) + return; + + if (apply) + player->AddTemporarySpell(_effectInfo->TriggerSpell); + else + player->RemoveTemporarySpell(_effectInfo->TriggerSpell); +} + void AuraEffect::HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 39b1cdf3eb8..7d1df37eb42 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -304,6 +304,7 @@ class TC_GAME_API AuraEffect void HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleShowConfirmationPrompt(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAllowUsingGameobjectsWhileMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 521abd26e7b..790e4abd3f0 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1774,6 +1774,10 @@ bool Aura::CanStackWith(Aura const* existingAura) const return true; // Empty seat available (skip rest) } + if (HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT) || HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY)) + if (existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY) || existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY)) + return false; + // spell of same spell rank chain if (m_spellInfo->IsRankOf(existingSpellInfo)) { -- cgit v1.2.3 From e78abe9911855a86c5dad543ac78edf5d87ed2f6 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 31 May 2016 17:02:22 +0200 Subject: Core/Auras: Fix copypaste mistake from fde9e8985f203048f07909bf0d3b0865cda55c42 --- src/server/game/Spells/Auras/SpellAuras.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 790e4abd3f0..e7c932e8a3b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1775,7 +1775,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const } if (HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT) || HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY)) - if (existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY) || existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY)) + if (existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT) || existingAura->HasEffectType(SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY)) return false; // spell of same spell rank chain -- cgit v1.2.3 From 2cead228d298392c2cf86046488594cd1b164aa3 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 31 May 2016 17:03:05 +0200 Subject: Core/PacketIO: Fixed setting player declined names Closes #16669 --- src/server/game/Server/Protocol/Opcodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c69d3613ada..7dd7b2dc3e9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -695,7 +695,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_PARTY_ASSIGNMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetPartyAssignment, &WorldSession::HandleSetPartyAssignment); DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetPartyLeader, &WorldSession::HandleSetPartyLeaderOpcode); DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetPlayerDeclinedNames, &WorldSession::HandleSetPlayerDeclinedNames); + DEFINE_HANDLER(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::SetPlayerDeclinedNames, &WorldSession::HandleSetPlayerDeclinedNames); DEFINE_HANDLER(CMSG_SET_PREFERRED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetPvP, &WorldSession::HandleSetPvP); DEFINE_HANDLER(CMSG_SET_RAID_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetRaidDifficulty, &WorldSession::HandleSetRaidDifficultyOpcode); -- cgit v1.2.3 From 3ccb1e665fcab401aa66b3d5796b835a72e768d0 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 1 Jun 2016 23:08:30 +0200 Subject: Core/Auras: Send aura update to client when aura amount changes and aura has SPELL_ATTR8_AURA_SEND_AMOUNT --- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index d3fc6c5e592..3272eedc265 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -851,6 +851,9 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply) for (std::list::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr) if ((*apptItr)->HasEffect(GetEffIndex())) HandleEffect(*apptItr, handleMask, true); + + if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) + GetBase()->SetNeedClientUpdateForTargets(); } void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply) -- cgit v1.2.3 From 63f8f54e5c1efd379ce8758a19c6b9ebfec43ed8 Mon Sep 17 00:00:00 2001 From: Shocker Date: Thu, 2 Jun 2016 17:07:07 +0300 Subject: Core/Spells: Define SPELL_EFFECT_ALTER_ITEM --- src/server/game/Miscellaneous/SharedDefines.h | 2 +- src/server/game/Spells/SpellEffects.cpp | 2 +- src/server/game/Spells/SpellInfo.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index e9f6c3f3aff..b836611609e 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1213,7 +1213,7 @@ enum SpellEffectName SPELL_EFFECT_203 = 203, SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY = 204, SPELL_EFFECT_LAUNCH_QUEST_CHOICE = 205, - SPELL_EFFECT_206 = 206, + SPELL_EFFECT_ALTER_ITEM = 206, // NYI SPELL_EFFECT_LAUNCH_QUEST_TASK = 207, // Starts one of the "progress bar" quests SPELL_EFFECT_208 = 208, SPELL_EFFECT_209 = 209, diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b72c03dc08a..71ab0858534 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -271,7 +271,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //203 SPELL_EFFECT_203 &Spell::EffectNULL, //204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY &Spell::EffectNULL, //205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE - &Spell::EffectNULL, //206 SPELL_EFFECT_206 + &Spell::EffectNULL, //206 SPELL_EFFECT_ALTER_ITEM &Spell::EffectNULL, //207 SPELL_EFFECT_LAUNCH_QUEST_TASK &Spell::EffectNULL, //208 SPELL_EFFECT_208 &Spell::EffectNULL, //209 SPELL_EFFECT_209 diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 28ac49fde1f..72f30e14dac 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -928,7 +928,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 203 SPELL_EFFECT_203 {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE - {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 206 SPELL_EFFECT_206 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_ITEM}, // 206 SPELL_EFFECT_ALTER_IETM {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 207 SPELL_EFFECT_LAUNCH_QUEST_TASK {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 208 SPELL_EFFECT_208 {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 209 SPELL_EFFECT_209 -- cgit v1.2.3 From 9db75766e77b69295551c987eaa2b965a7c6f45c Mon Sep 17 00:00:00 2001 From: Sean Rhone Date: Thu, 2 Jun 2016 19:35:24 -0400 Subject: Update worldserver.conf.dist (#17270) - Very minor typo --- src/server/worldserver/worldserver.conf.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 83313537cdb..87d76c3f8a1 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3301,7 +3301,7 @@ AuctionHouseBot.Items.Amount.Yellow = 0 # Armor: 8 # Reagent: 1 # Projectile: 2 -# TradeGod: 10 +# TradeGood: 10 # Generic: 1 # Recipe: 6 # Quiver: 1 -- cgit v1.2.3 From 2c2bb4a2377b40af2fccd484b13993aa16ad6380 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 3 Jun 2016 23:27:07 +0200 Subject: Core/Auras: Named currency gain modifying aura types --- src/server/game/Spells/Auras/SpellAuraDefines.h | 4 ++-- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 1d1de78b18b..4588b134614 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -433,7 +433,7 @@ enum AuraType SPELL_AURA_373 = 373, SPELL_AURA_MODIFY_FALL_DAMAGE_PCT = 374, // NYI SPELL_AURA_375 = 375, - SPELL_AURA_MOD_CURRENCY_GAIN_2 = 376, // NYI + SPELL_AURA_MOD_CURRENCY_GAIN_FROM_SOURCE = 376, // NYI SPELL_AURA_CAST_WHILE_WALKING_2 = 377, // NYI SPELL_AURA_378 = 378, SPELL_AURA_379 = 379, @@ -533,7 +533,7 @@ enum AuraType SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT = 473, // Prevents durability loss from dealing/taking damage SPELL_AURA_474 = 474, SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED = 475, - SPELL_AURA_476 = 476, + SPELL_AURA_MOD_CURRENCY_GAIN_LOOTED = 476, SPELL_AURA_477 = 477, SPELL_AURA_478 = 478, SPELL_AURA_479 = 479, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 3272eedc265..40db543002b 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -435,7 +435,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //373 &AuraEffect::HandleNULL, //374 SPELL_AURA_MODIFY_FALL_DAMAGE_PCT &AuraEffect::HandleNULL, //375 - &AuraEffect::HandleNULL, //376 SPELL_AURA_MOD_CURRENCY_GAIN_2 + &AuraEffect::HandleNULL, //376 SPELL_AURA_MOD_CURRENCY_GAIN_FROM_SOURCE &AuraEffect::HandleNULL, //377 SPELL_AURA_CAST_WHILE_WALKING_2 &AuraEffect::HandleNULL, //378 &AuraEffect::HandleNULL, //379 @@ -535,7 +535,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //473 SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT implemented in Player::DurabilityPointLossForEquipSlot &AuraEffect::HandleNULL, //474 &AuraEffect::HandleAllowUsingGameobjectsWhileMounted, //475 SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED - &AuraEffect::HandleNULL, //476 + &AuraEffect::HandleNULL, //476 SPELL_AURA_MOD_CURRENCY_GAIN_LOOTED &AuraEffect::HandleNULL, //477 &AuraEffect::HandleNULL, //478 &AuraEffect::HandleNULL, //479 -- cgit v1.2.3 From 8b26aea95a301af5a6af888df4fd3e7683e1ef62 Mon Sep 17 00:00:00 2001 From: DDuarte Date: Sat, 4 Jun 2016 11:26:57 +0100 Subject: Implement real time statistic visualization (#16956) Docs at https://trinitycore.atlassian.net/wiki/display/tc/Monitoring+a+TrinityCore+server * Common/Graphs: Initial proof of concept * Move influx db code to its own class * Reuse the same socket * Allow to log values of different categories * Allow to log events * Pass the timestamp to influxdb * Send events in batches * Send data async * Log server shutdown. Fix memory leak. * Allow to enable/disable Stats in the settings and at runtime * Read interval between each batch send from config * Add InfluxDB connection info to configs * Move each event category to its own table * Log pathfinding queries * Move categories table initialization to constructor using enum as key to avoid assigning the table name to the wrong enum value * Log player login/logout events. Pass the hostname correctly in the HTTP request. * Fix linux build * Handle "Connection: close" HTTP header, reconnecting on next scheduled send. Disable StatsLogger if connection fails, logging the error. * Add an enum for categories of logged values, it's still possible to pass a string instead of the enum. * Don't log the whole batchedData when InfluxDB returns an error, it's too long and unreadable on console. * Allow to call a function at a specified interval in thread-safe World::Update() context to log data like player count. * Log map tile load/unload * Core/StatsLogger: Allow logging more value types other than ints https://docs.influxdata.com/influxdb/v0.10/write_protocols/write_syntax/ * Fix a typo in string escape of StatsLogger * Yet more fixes to the escaping in FormatInfluxDBValue * DB/Gameobject: Fix respawn time of few Quest GameObjects By Tauriella, closes #16701 * DB/Misc: Fix some engrish By tkrokli closes #16648 * Tools/MMaps: Add format library linking to mmaps_generator (Very) partial cherry pick of ed75b0649add23e082976fa4e5d504bc0c312602 * Core/StatsLogger: Simplify code Convert values and categories arrays to maps initialized in-place Remove constructor and destructor * Core/StatsLogger: Add realm name to the event and value tags * Log amount of processed packet of each session * Apply recent singleton changes to sStatsLogger too * Fix influxdb data format if no realm name is present * Remove unneeded newlines from request body, fixes response 400 from InfluxDB 0.10 * Rename Reporting folder to Metric * Rename StatsLogger to Metric * Rename InfluxDB configs to Metric * Add Grafana dashboards * Add a random annoying macro * Move string formatting to Metric::SendBatch(), reducing performance footprint of Metric::LogEvent() and Metric::LogValue() * Update grafana graphs refresing tags on load and showing now-15m data, refreshing every minute. These settings can be modified in grafana. * Rename MetricData fields * Contrib/Grafana: Rename dashboard files * Contrib/Grafana: Replace hardcoded Windows/Ubuntu realm names by the default, Trinity * Config/Worldserver: Add missing section to the index * Contrib/Grafana: Add singlestat panels with current online players, update diff averages (1 min, 5 mins and 15 mins) http://i.imgur.com/Zi8lfvS.png * Core/Metric: Replace the enums MetricEventCategory and MetricValueCategory by strings For the sake of simplicity and less recompile time when adding new metrics, similar to how TC_LOG_* works * Contrib/Grafana: Display the current number of online players and not its average Closes #15075 (cherry picked from commit 3ae10160820782d039c3449107960108fb3a63b9) # Conflicts: # src/server/game/Server/WorldSession.cpp # src/server/game/World/World.cpp # src/server/worldserver/Main.cpp --- contrib/grafana/1_General.json | 889 ++++++++++++++++++++++++++ contrib/grafana/2_Maps.json | 339 ++++++++++ contrib/grafana/3_Network.json | 242 +++++++ src/common/Collision/Maps/MapTree.cpp | 5 + src/common/Metric/Metric.cpp | 235 +++++++ src/common/Metric/Metric.h | 141 ++++ src/server/game/Handlers/CharacterHandler.cpp | 3 + src/server/game/Movement/PathGenerator.cpp | 3 + src/server/game/Server/WorldSession.cpp | 5 + src/server/game/World/World.cpp | 8 + src/server/worldserver/Main.cpp | 11 + src/server/worldserver/worldserver.conf.dist | 39 ++ 12 files changed, 1920 insertions(+) create mode 100644 contrib/grafana/1_General.json create mode 100644 contrib/grafana/2_Maps.json create mode 100644 contrib/grafana/3_Network.json create mode 100644 src/common/Metric/Metric.cpp create mode 100644 src/common/Metric/Metric.h (limited to 'src') diff --git a/contrib/grafana/1_General.json b/contrib/grafana/1_General.json new file mode 100644 index 00000000000..96b0c9170af --- /dev/null +++ b/contrib/grafana/1_General.json @@ -0,0 +1,889 @@ +{ + "id": 1, + "title": "General info", + "originalTitle": "General info", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "25px", + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "editable": true, + "error": false, + "format": "none", + "id": 5, + "interval": null, + "isNew": true, + "links": [], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + } + ], + "measurement": "online_players", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "type": "field", + "params": [ + "value" + ] + }, + { + "type": "last", + "params": [] + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "title": "Online players", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current", + "timeFrom": null, + "timeShift": null, + "hideTimeOverride": false + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "editable": true, + "error": false, + "format": "none", + "id": 6, + "interval": null, + "isNew": true, + "links": [], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "title": "Update diff (avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg", + "timeFrom": "1m" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "editable": true, + "error": false, + "format": "none", + "id": 7, + "interval": null, + "isNew": true, + "links": [], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Update diff (avg)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg", + "timeFrom": "5m" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "editable": true, + "error": false, + "format": "none", + "id": 8, + "interval": null, + "isNew": true, + "links": [], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "auto" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/^$realm$/" + } + ] + } + ], + "thresholds": "", + "title": "Update diff (avg)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg", + "timeFrom": "15m", + "timeShift": null + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Update diff", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "update_time_diff", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"update_time_diff\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(null)", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Update diff", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "show": true + }, + "y-axis": true, + "y_formats": [ + "ms", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "Row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 4, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Online players", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "online_players", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"online_players\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(null)", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Online players", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "show": true + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 3, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Logouts", + "transform": "negative-Y" + } + ], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Logins", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "player_events", + "policy": "default", + "query": "SELECT count(\"text\") FROM \"player_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'Login' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "text" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=", + "value": "Trinity" + } + ] + }, + { + "alias": "Logouts", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "policy": "default", + "query": "SELECT count(\"text\") FROM \"player_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'Logout' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Player login/logout", + "tooltip": { + "msResolution": false, + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "show": true + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + } + ], + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [ + { + "allFormat": "regex values", + "current": { + "text": "Trinity", + "value": "Trinity" + }, + "datasource": null, + "includeAll": false, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [ + { + "text": "Trinity", + "value": "Trinity", + "selected": true + } + ], + "query": "show tag values from events with key = realm", + "refresh": 1, + "regex": "", + "type": "query" + } + ] + }, + "annotations": { + "list": [ + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "refresh": "1m", + "schemaVersion": 12, + "version": 7, + "links": [] +} \ No newline at end of file diff --git a/contrib/grafana/2_Maps.json b/contrib/grafana/2_Maps.json new file mode 100644 index 00000000000..6c2cecb1035 --- /dev/null +++ b/contrib/grafana/2_Maps.json @@ -0,0 +1,339 @@ +{ + "id": 2, + "title": "Maps, vmaps and mmaps", + "originalTitle": "Maps, vmaps and mmaps", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 2, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Unload tile", + "transform": "negative-Y" + } + ], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Load tile", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"map_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'LoadMapTile' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Unload tile", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"map_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'UnloadMapTile' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Map", + "tooltip": { + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "y-axis": true, + "y_formats": [ + "short", + "short" + ] + } + ], + "title": "Row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Pathfinding queries", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "query": "SELECT count(\"title\") FROM \"mmap_events\" WHERE \"realm\" =~ /$realm$/ AND \"title\" = 'CalculatePath' AND $timeFilter GROUP BY time($interval) fill(0)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "MMap", + "tooltip": { + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "y-axis": true, + "y_formats": [ + "short", + "short" + ] + } + ], + "title": "New row" + } + ], + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [ + { + "allFormat": "regex values", + "current": { + "text": "Trinity", + "value": "Trinity" + }, + "datasource": "Influx", + "includeAll": false, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [ + { + "text": "Trinity", + "value": "Trinity", + "selected": true + } + ], + "query": "show tag values from events with key = realm", + "refresh": true, + "type": "query" + } + ] + }, + "annotations": { + "list": [ + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "refresh": "1m", + "schemaVersion": 8, + "version": 11, + "links": [] +} \ No newline at end of file diff --git a/contrib/grafana/3_Network.json b/contrib/grafana/3_Network.json new file mode 100644 index 00000000000..98c190e1185 --- /dev/null +++ b/contrib/grafana/3_Network.json @@ -0,0 +1,242 @@ +{ + "id": 3, + "title": "Network", + "originalTitle": "Network", + "tags": [], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Influx", + "editable": true, + "error": false, + "fill": 1, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null, + "threshold1": null, + "threshold1Color": "rgba(216, 200, 27, 0.27)", + "threshold2": null, + "threshold2Color": "rgba(234, 112, 112, 0.22)" + }, + "id": 1, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Processed packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "processed_packets", + "query": "SELECT sum(\"value\") FROM \"processed_packets\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(0)", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + }, + { + "alias": "Processed packets / mean per session", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "processed_packets", + "query": "SELECT mean(\"value\") FROM \"processed_packets\" WHERE \"realm\" =~ /$realm$/ AND $timeFilter GROUP BY time($interval) fill(0)", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "realm", + "operator": "=~", + "value": "/$realm$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Processed packets", + "tooltip": { + "shared": true, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "y-axis": true, + "y_formats": [ + "short", + "short" + ] + } + ], + "title": "Row" + } + ], + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [ + { + "allFormat": "regex values", + "current": { + "text": "Trinity", + "value": "Trinity" + }, + "datasource": "Influx", + "includeAll": false, + "multi": false, + "multiFormat": "regex values", + "name": "realm", + "options": [ + { + "text": "Trinity", + "value": "Trinity", + "selected": true + } + ], + "query": "show tag values from events with key = realm", + "refresh": true, + "type": "query" + } + ] + }, + "annotations": { + "list": [ + { + "datasource": "Influx", + "enable": true, + "iconColor": "#C0C6BE", + "iconSize": 13, + "lineColor": "rgba(255, 96, 96, 0.592157)", + "name": "Global Events", + "query": "select title, text from events where $timeFilter and realm =~ /$realm$/", + "showLine": true, + "textColumn": "text", + "titleColumn": "title" + } + ] + }, + "refresh": "1m", + "schemaVersion": 8, + "version": 7, + "links": [] +} \ No newline at end of file diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index faabdbdffb8..b7b98199502 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -22,6 +22,7 @@ #include "VMapDefinitions.h" #include "Log.h" #include "Errors.h" +#include "Metric.h" #include #include @@ -415,6 +416,8 @@ namespace VMAP } else iLoadedTiles[packTileID(tileX, tileY)] = false; + TC_METRIC_EVENT("map_events", "LoadMapTile", + "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY)); return result; } @@ -473,6 +476,8 @@ namespace VMAP } } iLoadedTiles.erase(tile); + TC_METRIC_EVENT("map_events", "UnloadMapTile", + "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY)); } void StaticMapTree::getModelInstances(ModelInstance* &models, uint32 &count) diff --git a/src/common/Metric/Metric.cpp b/src/common/Metric/Metric.cpp new file mode 100644 index 00000000000..9484cebcc72 --- /dev/null +++ b/src/common/Metric/Metric.cpp @@ -0,0 +1,235 @@ +/* +* Copyright (C) 2008-2016 TrinityCore +* +* 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 . +*/ + +#include "Metric.h" +#include "Log.h" +#include "Config.h" +#include "Util.h" + +void Metric::Initialize(std::string const& realmName, boost::asio::io_service& ioService, std::function overallStatusLogger) +{ + _realmName = realmName; + _batchTimer = Trinity::make_unique(ioService); + _overallStatusTimer = Trinity::make_unique(ioService); + _overallStatusLogger = overallStatusLogger; + LoadFromConfigs(); +} + +bool Metric::Connect() +{ + _dataStream.connect(_hostname, _port); + auto error = _dataStream.error(); + if (error) + { + TC_LOG_ERROR("metric", "Error connecting to '%s:%s', disabling Metric. Error message : %s", + _hostname.c_str(), _port.c_str(), error.message().c_str()); + _enabled = false; + return false; + } + _dataStream.clear(); + return true; +} + +void Metric::LoadFromConfigs() +{ + bool previousValue = _enabled; + _enabled = sConfigMgr->GetBoolDefault("Metric.Enable", false); + _updateInterval = sConfigMgr->GetIntDefault("Metric.Interval", 10); + if (_updateInterval < 1) + { + TC_LOG_ERROR("metric", "'Metric.Interval' config set to %d, overriding to 1.", _updateInterval); + _updateInterval = 1; + } + + _overallStatusTimerInterval = sConfigMgr->GetIntDefault("Metric.OverallStatusInterval", 1); + if (_overallStatusTimerInterval < 1) + { + TC_LOG_ERROR("metric", "'Metric.OverallStatusInterval' config set to %d, overriding to 1.", _overallStatusTimerInterval); + _overallStatusTimerInterval = 1; + } + + // Schedule a send at this point only if the config changed from Disabled to Enabled. + // Cancel any scheduled operation if the config changed from Enabled to Disabled. + if (_enabled && !previousValue) + { + std::string connectionInfo = sConfigMgr->GetStringDefault("Metric.ConnectionInfo", ""); + if (connectionInfo.empty()) + { + TC_LOG_ERROR("metric", "'Metric.ConnectionInfo' not specified in configuration file."); + return; + } + + Tokenizer tokens(connectionInfo, ';'); + if (tokens.size() != 3) + { + TC_LOG_ERROR("metric", "'Metric.ConnectionInfo' specified with wrong format in configuration file."); + return; + } + + _hostname.assign(tokens[0]); + _port.assign(tokens[1]); + _databaseName.assign(tokens[2]); + Connect(); + + ScheduleSend(); + ScheduleOverallStatusLog(); + } +} + +void Metric::Update() +{ + if (_overallStatusTimerTriggered) + { + _overallStatusTimerTriggered = false; + _overallStatusLogger(); + } +} + +void Metric::LogEvent(std::string const& category, std::string const& title, std::string const& description) +{ + using namespace std::chrono; + + MetricData* data = new MetricData; + data->Category = category; + data->Timestamp = system_clock::now(); + data->Type = METRIC_DATA_EVENT; + data->Title = title; + data->Text = description; + + _queuedData.Enqueue(data); +} + +void Metric::SendBatch() +{ + using namespace std::chrono; + + std::stringstream batchedData; + MetricData* data; + bool firstLoop = true; + while (_queuedData.Dequeue(data)) + { + if (!firstLoop) + batchedData << "\n"; + + batchedData << data->Category; + if (!_realmName.empty()) + batchedData << ",realm=" << _realmName; + + batchedData << " "; + + switch (data->Type) + { + case METRIC_DATA_VALUE: + batchedData << "value=" << data->Value; + break; + case METRIC_DATA_EVENT: + batchedData << "title=\"" << data->Title << "\",text=\"" << data->Text << "\""; + break; + } + + batchedData << " "; + + batchedData << std::to_string(duration_cast(data->Timestamp.time_since_epoch()).count()); + + firstLoop = false; + delete data; + } + + // Check if there's any data to send + if (batchedData.tellp() == std::streampos(0)) + { + ScheduleSend(); + return; + } + + if (!_dataStream.good() && !Connect()) + return; + + _dataStream << "POST " << "/write?db=" << _databaseName << " HTTP/1.1\r\n"; + _dataStream << "Host: " << _hostname << ":" << _port << "\r\n"; + _dataStream << "Accept: */*\r\n"; + _dataStream << "Content-Type: application/octet-stream\r\n"; + _dataStream << "Content-Transfer-Encoding: binary\r\n"; + + _dataStream << "Content-Length: " << std::to_string(batchedData.tellp()) << "\r\n\r\n"; + _dataStream << batchedData.rdbuf(); + + std::string http_version; + _dataStream >> http_version; + unsigned int status_code = 0; + _dataStream >> status_code; + if (status_code != 204) + { + TC_LOG_ERROR("metric", "Error sending data, returned HTTP code: %u", status_code); + } + + // Read and ignore the status description + std::string status_description; + std::getline(_dataStream, status_description); + // Read headers + std::string header; + while (std::getline(_dataStream, header) && header != "\r") + { + if (header == "Connection: close\r") + _dataStream.close(); + } + + ScheduleSend(); +} + +void Metric::ScheduleSend() +{ + if (_enabled) + { + _batchTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); + _batchTimer->async_wait(std::bind(&Metric::SendBatch, this)); + } + else + { + _dataStream.close(); + MetricData* data; + // Clear the queue + while (_queuedData.Dequeue(data)) + ; + } +} + +void Metric::ForceSend() +{ + // Send what's queued only if io_service is stopped (so only on shutdown) + if (_enabled && _batchTimer->get_io_service().stopped()) + SendBatch(); +} + +void Metric::ScheduleOverallStatusLog() +{ + if (_enabled) + { + _overallStatusTimer->expires_from_now(boost::posix_time::seconds(_overallStatusTimerInterval)); + _overallStatusTimer->async_wait([this](const boost::system::error_code&) + { + _overallStatusTimerTriggered = true; + ScheduleOverallStatusLog(); + }); + } +} + +Metric* Metric::instance() +{ + static Metric instance; + return &instance; +} diff --git a/src/common/Metric/Metric.h b/src/common/Metric/Metric.h new file mode 100644 index 00000000000..1855e1d0098 --- /dev/null +++ b/src/common/Metric/Metric.h @@ -0,0 +1,141 @@ +/* +* Copyright (C) 2008-2016 TrinityCore +* +* 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 . +*/ + +#ifndef METRIC_H__ +#define METRIC_H__ + +#include "Common.h" +#include "Threading/MPSCQueue.h" +#include +#include +#include + +enum MetricDataType +{ + METRIC_DATA_VALUE, + METRIC_DATA_EVENT +}; + +struct MetricData +{ + std::string Category; + std::chrono::time_point Timestamp; + MetricDataType Type; + + // LogValue-specific fields + std::string Value; + + // LogEvent-specific fields + std::string Title; + std::string Text; +}; + +class TC_COMMON_API Metric +{ +private: + boost::asio::ip::tcp::iostream _dataStream; + MPSCQueue _queuedData; + std::unique_ptr _batchTimer; + std::unique_ptr _overallStatusTimer; + int32 _updateInterval = 0; + int32 _overallStatusTimerInterval = 0; + bool _enabled = false; + bool _overallStatusTimerTriggered = false; + std::string _hostname; + std::string _port; + std::string _databaseName; + std::function _overallStatusLogger; + std::string _realmName; + + bool Connect(); + void SendBatch(); + void ScheduleSend(); + void ScheduleOverallStatusLog(); + + template::value>::type* = nullptr> + static std::string FormatInfluxDBValue(T value) { return std::to_string(value) + 'i'; } + + static std::string FormatInfluxDBValue(std::string const& value) + { + return '"' + boost::replace_all_copy(value, "\"", "\\\"") + '"'; + } + + static std::string FormatInfluxDBValue(bool value) { return value ? "t" : "f"; } + static std::string FormatInfluxDBValue(const char* value) { return FormatInfluxDBValue(std::string(value)); } + static std::string FormatInfluxDBValue(double value) { return std::to_string(value); } + static std::string FormatInfluxDBValue(float value) { return FormatInfluxDBValue(double(value)); } + +public: + static Metric* instance(); + + void Initialize(std::string const& realmName, boost::asio::io_service& ioService, std::function overallStatusLogger = [](){}); + void LoadFromConfigs(); + void Update(); + + template + void LogValue(std::string const& category, T value) + { + using namespace std::chrono; + + MetricData* data = new MetricData; + data->Category = category; + data->Timestamp = system_clock::now(); + data->Type = METRIC_DATA_VALUE; + data->Value = FormatInfluxDBValue(value); + + _queuedData.Enqueue(data); + } + + void LogEvent(std::string const& category, std::string const& title, std::string const& description); + + void ForceSend(); + bool IsEnabled() const { return _enabled; } +}; + +#define sMetric Metric::instance() + +#if PLATFORM != PLATFORM_WINDOWS +#define TC_METRIC_EVENT(category, title, description) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogEvent(category, title, description); \ + } while (0) +#define TC_METRIC_VALUE(category, value) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogValue(category, value); \ + } while (0) +#else +#define TC_METRIC_EVENT(category, title, description) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogEvent(category, title, description); \ + } while (0) \ + __pragma(warning(pop)) +#define TC_METRIC_VALUE(category, value) \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + do { \ + if (sMetric->IsEnabled()) \ + sMetric->LogValue(category, value); \ + } while (0) \ + __pragma(warning(pop)) +#endif + +#endif // METRIC_H__ diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ee1d69571f0..e4b03ed79c7 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -54,6 +54,7 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "Metric.h" class LoginQueryHolder : public SQLQueryHolder { @@ -1147,6 +1148,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); + TC_METRIC_EVENT("player_events", "Login", pCurrChar->GetName()); + delete holder; } diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index fe09aa26af2..39087269e54 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -26,6 +26,7 @@ #include "DisableMgr.h" #include "DetourCommon.h" #include "DetourNavMeshQuery.h" +#include "Metric.h" ////////////////// PathGenerator ////////////////// PathGenerator::PathGenerator(const Unit* owner) : @@ -62,6 +63,8 @@ bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool fo if (!Trinity::IsValidMapCoord(destX, destY, destZ) || !Trinity::IsValidMapCoord(x, y, z)) return false; + TC_METRIC_EVENT("mmap_events", "CalculatePath", ""); + G3D::Vector3 dest(destX, destY, destZ); SetEndPosition(dest); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 41141148922..c11c85aaffa 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -51,6 +51,7 @@ #include "BattlePetMgr.h" #include "PacketUtilities.h" #include "CollectionMgr.h" +#include "Metric.h" #include @@ -456,6 +457,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } + TC_METRIC_VALUE("processed_packets", processedPackets); + _recvQueue.readd(requeuePackets.begin(), requeuePackets.end()); if (m_Socket[CONNECTION_TYPE_REALM] && m_Socket[CONNECTION_TYPE_REALM]->IsOpen() && _warden) @@ -614,6 +617,8 @@ void WorldSession::LogoutPlayer(bool save) //! Call script hook before deletion sScriptMgr->OnPlayerLogout(_player); + TC_METRIC_EVENT("player_events", "Logout", _player->GetName()); + //! Remove the player from the world // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 61e1755b4e4..5513c8e94dd 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -63,6 +63,7 @@ #include "SkillDiscovery.h" #include "SkillExtraItems.h" #include "SmartAI.h" +#include "Metric.h" #include "SupportMgr.h" #include "TaxiPathGraph.h" #include "TransportMgr.h" @@ -437,6 +438,7 @@ void World::LoadConfigSettings(bool reload) return; } sLog->LoadFromConfig(); + sMetric->LoadFromConfigs(); } m_defaultDbcLocale = LocaleConstant(sConfigMgr->GetIntDefault("DBC.Locale", 0)); @@ -2128,6 +2130,8 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); + TC_METRIC_EVENT("events", "World initialized", "World initialized in " + std::to_string(startupDuration / 60000) + " minutes " + std::to_string((startupDuration % 60000) / 1000) + " seconds"); + if (uint32 realmId = sConfigMgr->GetIntDefault("RealmID", 0)) // 0 reserved for auth sLog->SetRealmId(realmId); } @@ -2430,6 +2434,10 @@ void World::Update(uint32 diff) ProcessCliCommands(); sScriptMgr->OnWorldUpdate(diff); + + // Stats logger update + sMetric->Update(); + TC_METRIC_VALUE("update_time_diff", diff); } void World::ForceGameEventUpdate() diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 5d8d0819102..2d14e3301a3 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -45,6 +45,7 @@ #include "RealmList.h" #include "DatabaseLoader.h" #include "AppenderDB.h" +#include "Metric.h" #include #include #include @@ -200,6 +201,13 @@ extern int main(int argc, char** argv) LoadRealmInfo(); + sMetric->Initialize(realm.Name, _ioService, []() + { + TC_METRIC_VALUE("online_players", sWorld->GetPlayerCount()); + }); + + TC_METRIC_EVENT("events", "Worldserver started", ""); + // Initialize the World sScriptMgr->SetScriptLoader(AddScripts); sWorld->SetInitialWorldSettings(); @@ -300,6 +308,9 @@ extern int main(int argc, char** argv) StopDB(); + TC_METRIC_EVENT("events", "Worldserver shutdown", ""); + sMetric->ForceSend(); + TC_LOG_INFO("server.worldserver", "Halting process..."); ShutdownCLIThread(cliThread); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 87d76c3f8a1..dcaad115812 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -37,6 +37,7 @@ # LOGGING SYSTEM SETTINGS # CURRENCIES SETTINGS # PACKET SPOOF PROTECTION SETTINGS +# METRIC SETTINGS # ################################################################################################### @@ -3853,3 +3854,41 @@ PacketSpoof.BanDuration = 86400 # ################################################################################################### + +################################################################################################### +# METRIC SETTINGS +# +# These settings control the statistics sent to the metric database (currently InfluxDB) +# +# Metric.Enable +# Description: Enables statistics sent to the metric database. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Metric.Enable = 0 + +# +# Metric.Interval +# Description: Interval between every batch of data sent in seconds +# Default: 10 seconds +# + +Metric.Interval = 10 + +# +# Metric.ConnectionInfo +# Description: Connection settings for metric database (currently InfluxDB). +# Example: "hostname;port;database" +# Default: "127.0.0.1;8086;worldserver" + +Metric.ConnectionInfo = "127.0.0.1;8086;worldserver" + +# +# Metric.OverallStatusInterval +# Description: Interval between every gathering of overall worldserver status data in seconds +# Default: 1 second +# + +Metric.OverallStatusInterval = 1 + +################################################################################################### -- cgit v1.2.3 From 1379505bf2c98318085eeebdc9912ba89439e78e Mon Sep 17 00:00:00 2001 From: Aokromes Date: Sat, 4 Jun 2016 12:49:07 +0200 Subject: Update worldserver.conf.dist --- src/server/worldserver/worldserver.conf.dist | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index dcaad115812..2bf6b42d703 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3891,4 +3891,5 @@ Metric.ConnectionInfo = "127.0.0.1;8086;worldserver" Metric.OverallStatusInterval = 1 +# ################################################################################################### -- cgit v1.2.3 From dd1533b315bda37e1d43ebe0fb8bde87381c6e66 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 4 Jun 2016 16:40:57 +0200 Subject: Core/Utils: Added additional argument to Tokenizer class to make it behave like strtok - not returning empty tokens in case of multiple consecutive separators in input string --- src/common/Utilities/Util.cpp | 7 ++++--- src/common/Utilities/Util.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 28ffc891034..4f758c9cff1 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -30,7 +30,7 @@ #include #endif -Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve) +Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve /*= 0*/, bool keepEmptyStrings /*= true*/) { m_str = new char[src.length() + 1]; memcpy(m_str, src.c_str(), src.length() + 1); @@ -45,9 +45,10 @@ Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserv { if (*posnew == sep) { - m_storage.push_back(posold); - posold = posnew + 1; + if (keepEmptyStrings || posold != posnew) + m_storage.push_back(posold); + posold = posnew + 1; *posnew = '\0'; } else if (*posnew == '\0') diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 7f0fc907964..ff737eb33bd 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -54,7 +54,7 @@ public: typedef StorageType::const_reference const_reference; public: - Tokenizer(const std::string &src, char const sep, uint32 vectorReserve = 0); + Tokenizer(const std::string &src, char const sep, uint32 vectorReserve = 0, bool keepEmptyStrings = true); ~Tokenizer() { delete[] m_str; } const_iterator begin() const { return m_storage.begin(); } -- cgit v1.2.3 From 6ce84d9401a630958d3aec11e69c1382c56d6bf9 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 5 Jun 2016 01:19:25 +0200 Subject: Core/PacketIO: Fixed sending SMSG_SPELL_EXECUTE_LOG --- src/server/game/Spells/Spell.cpp | 54 +++++++++++----------------------------- src/server/game/Spells/Spell.h | 1 - 2 files changed, 15 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index aa02dfa3f63..31bcfc39980 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -616,7 +616,6 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)), && !m_spellInfo->IsPassive() && !m_spellInfo->IsPositive(); CleanupTargetList(); - CleanupExecuteLogList(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) m_destTargets[i] = SpellDestination(*m_caster); @@ -645,7 +644,6 @@ Spell::~Spell() ASSERT(m_caster->ToPlayer()->m_spellModTakingSpell != this); delete m_spellValue; - CleanupExecuteLogList(); } void Spell::InitExplicitTargets(SpellCastTargets const& targets) @@ -4178,45 +4176,33 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo) void Spell::SendSpellExecuteLog() { WorldPackets::CombatLog::SpellExecuteLog spellExecuteLog; - spellExecuteLog.Caster = m_caster->GetGUID(); spellExecuteLog.SpellID = m_spellInfo->Id; - if (_powerDrainTargets->empty() && _extraAttacksTargets->empty() && - _durabilityDamageTargets->empty() && _genericVictimTargets->empty() && - _tradeSkillTargets->empty() && _feedPetTargets->empty()) - return; - for (SpellEffectInfo const* effect : GetEffects()) { - WorldPackets::CombatLog::SpellExecuteLog::SpellLogEffect spellLogEffect; if (!effect) continue; - spellLogEffect.Effect = effect->Effect; - - for (SpellLogEffectPowerDrainParams const& powerDrainParam : _powerDrainTargets[effect->EffectIndex]) - spellLogEffect.PowerDrainTargets.push_back(powerDrainParam); - - for (SpellLogEffectExtraAttacksParams const& extraAttacksTarget : _extraAttacksTargets[effect->EffectIndex]) - spellLogEffect.ExtraAttacksTargets.push_back(extraAttacksTarget); - - for (SpellLogEffectDurabilityDamageParams const& durabilityDamageTarget : _durabilityDamageTargets[effect->EffectIndex]) - spellLogEffect.DurabilityDamageTargets.push_back(durabilityDamageTarget); - - for (SpellLogEffectGenericVictimParams const& genericVictimTarget : _genericVictimTargets[effect->EffectIndex]) - spellLogEffect.GenericVictimTargets.push_back(genericVictimTarget); - - for (SpellLogEffectTradeSkillItemParams const& tradeSkillTarget : _tradeSkillTargets[effect->EffectIndex]) - spellLogEffect.TradeSkillTargets.push_back(tradeSkillTarget); + if (_powerDrainTargets[effect->EffectIndex].empty() && _extraAttacksTargets[effect->EffectIndex].empty() && + _durabilityDamageTargets[effect->EffectIndex].empty() && _genericVictimTargets[effect->EffectIndex].empty() && + _tradeSkillTargets[effect->EffectIndex].empty() && _feedPetTargets[effect->EffectIndex].empty()) + continue; - for (SpellLogEffectFeedPetParams const& feedPetTarget : _feedPetTargets[effect->EffectIndex]) - spellLogEffect.FeedPetTargets.push_back(feedPetTarget); + spellExecuteLog.Effects.emplace_back(); - spellExecuteLog.Effects.push_back(spellLogEffect); + WorldPackets::CombatLog::SpellExecuteLog::SpellLogEffect& spellLogEffect = spellExecuteLog.Effects.back(); + spellLogEffect.Effect = effect->Effect; + spellLogEffect.PowerDrainTargets = std::move(_powerDrainTargets[effect->EffectIndex]); + spellLogEffect.ExtraAttacksTargets = std::move(_extraAttacksTargets[effect->EffectIndex]); + spellLogEffect.DurabilityDamageTargets = std::move(_durabilityDamageTargets[effect->EffectIndex]); + spellLogEffect.GenericVictimTargets = std::move(_genericVictimTargets[effect->EffectIndex]); + spellLogEffect.TradeSkillTargets = std::move(_tradeSkillTargets[effect->EffectIndex]); + spellLogEffect.FeedPetTargets = std::move(_feedPetTargets[effect->EffectIndex]); } - m_caster->SendCombatLogMessage(&spellExecuteLog); + if (!spellExecuteLog.Effects.empty()) + m_caster->SendCombatLogMessage(&spellExecuteLog); } void Spell::ExecuteLogEffectTakeTargetPower(uint8 effIndex, Unit* target, uint32 powerType, uint32 points, float amplitude) @@ -4309,16 +4295,6 @@ void Spell::ExecuteLogEffectResurrect(uint8 effect, Unit* target) _genericVictimTargets[effect].push_back(spellLogEffectGenericVictimParams); } -void Spell::CleanupExecuteLogList() -{ - _durabilityDamageTargets->clear(); - _extraAttacksTargets->clear(); - _feedPetTargets->clear(); - _genericVictimTargets->clear(); - _powerDrainTargets->clear(); - _tradeSkillTargets->clear(); -} - void Spell::SendInterrupted(uint8 result) { WorldPackets::Spells::SpellFailure failurePacket; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 192ed942ce0..f08aa39b4c4 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -539,7 +539,6 @@ class TC_GAME_API Spell void ExecuteLogEffectSummonObject(uint8 effIndex, WorldObject* obj); void ExecuteLogEffectUnsummonObject(uint8 effIndex, WorldObject* obj); void ExecuteLogEffectResurrect(uint8 effIndex, Unit* target); - void CleanupExecuteLogList(); void SendInterrupted(uint8 result); void SendChannelUpdate(uint32 time); void SendChannelStart(uint32 duration); -- cgit v1.2.3 From 9d7a17d9f5f29c928e14d175479da68b2118add9 Mon Sep 17 00:00:00 2001 From: Vincent-Michael Date: Sun, 5 Jun 2016 16:43:41 +0200 Subject: Core/Commands: Added ".npc set phase" command error message for invalid phaseid Closes #14927 --- sql/updates/world/6.x/2016_06_05_04_world.sql | 3 +++ src/server/game/Miscellaneous/Language.h | 2 +- src/server/scripts/Commands/cs_npc.cpp | 12 +++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 sql/updates/world/6.x/2016_06_05_04_world.sql (limited to 'src') diff --git a/sql/updates/world/6.x/2016_06_05_04_world.sql b/sql/updates/world/6.x/2016_06_05_04_world.sql new file mode 100644 index 00000000000..36b52243afd --- /dev/null +++ b/sql/updates/world/6.x/2016_06_05_04_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `trinity_string` WHERE `entry`=5007; +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(5007,"Uses invalid phaseID."); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index a4051c7e865..6f1f4cb2409 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1069,7 +1069,7 @@ enum TrinityStrings LANG_COMMAND_NO_FROZEN_PLAYERS = 5004, LANG_COMMAND_LIST_FREEZE = 5005, LANG_COMMAND_PERMA_FROZEN_PLAYER = 5006, - // = 5007, unused + LANG_PHASE_NOTFOUND = 5007, LANG_INSTANCE_CLOSED = 5008, LANG_COMMAND_PLAYED_TO_ALL = 5009, LANG_NPCINFO_LINKGUID = 5010, diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index d9d54353246..c71e0f01940 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1106,7 +1106,13 @@ public: if (!*args) return false; - uint32 phase = (uint32) atoi((char*)args); + uint32 phaseID = uint32(atoi((char*)args)); + if (!sPhaseStore.LookupEntry(phaseID)) + { + handler->SendSysMessage(LANG_PHASE_NOTFOUND); + handler->SetSentErrorMessage(true); + return false; + } Creature* creature = handler->getSelectedCreature(); if (!creature || creature->IsPet()) @@ -1117,8 +1123,8 @@ public: } creature->ClearPhases(); - creature->SetInPhase(phase, true, true); - creature->SetDBPhase(phase); + creature->SetInPhase(phaseID, true, true); + creature->SetDBPhase(phaseID); creature->SaveToDB(); -- cgit v1.2.3 From 1c139214b5ffbae993d4162c555c81cf45b52228 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 6 Jun 2016 08:38:39 +0200 Subject: Core/Spells: Silence coverity false positive - CID 1356246 --- src/server/scripts/Spells/spell_shaman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index d41dcb42411..7ad37ba5bc2 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -442,7 +442,7 @@ class spell_sha_fulmination : public SpellScriptLoader uint32 stacks = aura->GetCharges(); if (stacks > 1) { - SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(aura->GetSpellEffectInfo(EFFECT_0)->TriggerSpell); + SpellInfo const* triggerSpell = sSpellMgr->AssertSpellInfo(aura->GetSpellEffectInfo(EFFECT_0)->TriggerSpell); SpellEffectInfo const* triggerEffect = triggerSpell->GetEffect(EFFECT_0); uint32 damage; -- cgit v1.2.3 From b920d6a35c0977c6bc806558b26d14c2fd351a97 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 6 Jun 2016 08:45:09 +0200 Subject: Core/Spells: Fixed possible null pointer dereference Coverity CID 1355243 --- src/server/game/Spells/SpellInfo.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 72f30e14dac..e7ac181e69f 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2820,6 +2820,9 @@ inline float CalcPPMItemLevelMod(SpellProcsPerMinuteModEntry const* mod, int32 i float SpellInfo::CalcProcPPM(Unit* caster, int32 itemLevel) const { float ppm = ProcBasePPM; + if (!caster) + return ppm; + for (SpellProcsPerMinuteModEntry const* mod : ProcPPMMods) { switch (mod->Type) -- cgit v1.2.3 From d8e0ce4d4009c707e99163d35214d24776b5c6bb Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 6 Jun 2016 08:49:10 +0200 Subject: Core/Misc: Fixed uninitialized fields in black market packets Coverity CID 1354736 and 1354737 --- src/server/game/Server/Packets/BlackMarketPackets.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/game/Server/Packets/BlackMarketPackets.h b/src/server/game/Server/Packets/BlackMarketPackets.h index 1193a9f0147..19853a212a5 100644 --- a/src/server/game/Server/Packets/BlackMarketPackets.h +++ b/src/server/game/Server/Packets/BlackMarketPackets.h @@ -122,7 +122,7 @@ namespace WorldPackets int32 MarketID = 0; Item::ItemInstance Item; - int32 RandomPropertiesID; + int32 RandomPropertiesID = 0; }; class BlackMarketWon final : public ServerPacket @@ -134,7 +134,7 @@ namespace WorldPackets int32 MarketID = 0; Item::ItemInstance Item; - int32 RandomPropertiesID; + int32 RandomPropertiesID = 0; }; } } -- cgit v1.2.3 From d59bba3c5dcc0915247c86c4b89f0325b2af97be Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 6 Jun 2016 08:51:42 +0200 Subject: Core/Misc: Fixed uninitialized field Coverity CID 1354596 --- src/server/bnetserver/REST/LoginRESTService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/bnetserver/REST/LoginRESTService.h b/src/server/bnetserver/REST/LoginRESTService.h index 5c78ef3e09d..881c656f15e 100644 --- a/src/server/bnetserver/REST/LoginRESTService.h +++ b/src/server/bnetserver/REST/LoginRESTService.h @@ -35,7 +35,7 @@ struct soap_plugin; class LoginRESTService { public: - LoginRESTService() : _stopped(false), _port(0) { } + LoginRESTService() : _stopped(false), _port(0), _loginTicketCleanupTimer(nullptr) { } static LoginRESTService& Instance(); -- cgit v1.2.3 From 8396dabdad65fbe86c525584e38ccfacde85f9f1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 6 Jun 2016 09:16:59 +0200 Subject: Core/Misc: Fixed coverity issues Uninitialized fields: CID 1354593, 1354595, 1354738 Unchecked return value: CID 1354558 Out of bounds access: CID 1352989, 1352993 Null pointer dereference: CID 1296286 --- src/server/bnetserver/Server/Session.cpp | 2 +- src/server/game/Entities/Unit/StatSystem.cpp | 2 +- src/server/game/Handlers/CharacterHandler.cpp | 4 +-- src/server/game/Handlers/PetHandler.cpp | 17 ++++++------ src/server/game/Server/Packets/BattlenetPackets.h | 4 +-- src/server/game/Server/Packets/PetPackets.cpp | 14 +++++----- src/server/game/Server/Packets/PetPackets.h | 3 +-- src/server/game/Server/WorldSession.cpp | 1 + .../scripts/Northrend/Naxxramas/boss_gluth.cpp | 30 ++++++++++++---------- 9 files changed, 39 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 66d55480796..844f80cba06 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -647,7 +647,7 @@ bool Battlenet::Session::ReadHeaderHandler() bool Battlenet::Session::ReadDataHandler() { Header header; - header.ParseFromArray(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize()); + ASSERT(header.ParseFromArray(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize())); if (header.service_id() != 0xFE) { diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index f5660efe00e..4fa79a91eee 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -302,7 +302,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) float val2 = 0.0f; float level = float(getLevel()); - ChrClassesEntry const* entry = sChrClassesStore.LookupEntry(getClass()); + ChrClassesEntry const* entry = sChrClassesStore.AssertEntry(getClass()); UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e4b03ed79c7..c1455d355d7 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -2210,8 +2210,8 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res uint32 title_alliance = it->first; uint32 title_horde = it->second; - CharTitlesEntry const* atitleInfo = sCharTitlesStore.LookupEntry(title_alliance); - CharTitlesEntry const* htitleInfo = sCharTitlesStore.LookupEntry(title_horde); + CharTitlesEntry const* atitleInfo = sCharTitlesStore.AssertEntry(title_alliance); + CharTitlesEntry const* htitleInfo = sCharTitlesStore.AssertEntry(title_horde); // new team if (newTeamId == TEAM_ALLIANCE) { diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 849a5097c61..84b89968dfb 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -515,10 +515,9 @@ void WorldSession::HandlePetSetAction(WorldPackets::Pet::PetSetAction& packet) void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) { ObjectGuid petguid = packet.RenameData.PetGUID; - bool isdeclined = packet.RenameData.HasDeclinedNames; std::string name = packet.RenameData.NewName; - DeclinedName declinedname = packet.RenameData.DeclinedNames; + DeclinedName* declinedname = packet.RenameData.DeclinedNames.get_ptr(); Pet* pet = ObjectAccessor::GetPet(*_player, petguid); // check it! @@ -546,21 +545,21 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); - if (isdeclined) + if (declinedname) { std::wstring wname; if (!Utf8toWStr(name, wname)) return; - if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) + if (!ObjectMgr::CheckDeclinedNames(wname, *declinedname)) { - SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); + SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, declinedname); return; } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (isdeclined) + if (declinedname) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME); stmt->setUInt32(0, pet->GetCharmInfo()->GetPetNumber()); @@ -571,7 +570,7 @@ void WorldSession::HandlePetRename(WorldPackets::Pet::PetRename& packet) stmt->setUInt64(1, _player->GetGUID().GetCounter()); for (uint8 i = 0; i < 5; i++) - stmt->setString(i + 2, declinedname.name[i]); + stmt->setString(i + 2, declinedname->name[i]); trans->Append(stmt); } @@ -717,8 +716,8 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec WorldPackets::Pet::PetNameInvalid petNameInvalid; petNameInvalid.Result = error; petNameInvalid.RenameData.NewName = name; - for (int i = 0; i < MAX_DECLINED_NAME_CASES; i++) - petNameInvalid.RenameData.DeclinedNames.name[i] = declinedName[i].name[i]; + if (declinedName) + petNameInvalid.RenameData.DeclinedNames = *declinedName; SendPacket(petNameInvalid.Write()); } diff --git a/src/server/game/Server/Packets/BattlenetPackets.h b/src/server/game/Server/Packets/BattlenetPackets.h index f059b39b75f..76aa499799c 100644 --- a/src/server/game/Server/Packets/BattlenetPackets.h +++ b/src/server/game/Server/Packets/BattlenetPackets.h @@ -76,8 +76,8 @@ namespace WorldPackets WorldPacket const* Write() override; - uint32 Token; - bool Allow; + uint32 Token = 0; + bool Allow = false; ByteBuffer Ticket; }; diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index 36a71ba9c53..8bbf0b051e4 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -99,19 +99,19 @@ WorldPacket const* WorldPackets::Pet::PetNameInvalid::Write() _worldPacket << uint8(RenameData.NewName.length()); - _worldPacket.WriteBit(RenameData.HasDeclinedNames); + _worldPacket.WriteBit(RenameData.DeclinedNames.is_initialized()); _worldPacket.FlushBits(); - if (RenameData.HasDeclinedNames) + if (RenameData.DeclinedNames) { for (int32 i = 0; i < MAX_DECLINED_NAME_CASES; i++) { - _worldPacket.WriteBits(RenameData.DeclinedNames.name[i].length(), 7); + _worldPacket.WriteBits(RenameData.DeclinedNames->name[i].length(), 7); _worldPacket.FlushBits(); } for (int32 i = 0; i < MAX_DECLINED_NAME_CASES; i++) - _worldPacket << RenameData.DeclinedNames.name[i]; + _worldPacket << RenameData.DeclinedNames->name[i]; } _worldPacket.WriteString(RenameData.NewName); @@ -126,15 +126,15 @@ void WorldPackets::Pet::PetRename::Read() int8 nameLen = 0; _worldPacket >> nameLen; - RenameData.HasDeclinedNames = _worldPacket.ReadBit(); - if (RenameData.HasDeclinedNames) + if (_worldPacket.ReadBit()) { + RenameData.DeclinedNames = boost::in_place(); int32 count[MAX_DECLINED_NAME_CASES]; for (int32 i = 0; i < MAX_DECLINED_NAME_CASES; i++) count[i] = _worldPacket.ReadBits(7); for (int32 i = 0; i < MAX_DECLINED_NAME_CASES; i++) - RenameData.DeclinedNames.name[i] = _worldPacket.ReadString(count[i]); + RenameData.DeclinedNames->name[i] = _worldPacket.ReadString(count[i]); } RenameData.NewName = _worldPacket.ReadString(nameLen); diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index f11a71a936c..3d3c3e76f72 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -163,8 +163,7 @@ namespace WorldPackets ObjectGuid PetGUID; int32 PetNumber = 0; std::string NewName; - bool HasDeclinedNames = false; - DeclinedName DeclinedNames; + Optional DeclinedNames; }; class PetNameInvalid final : public ServerPacket diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index c11c85aaffa..59f18bc79b0 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -118,6 +118,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun _battlenetAccountId(battlenetAccountId), m_expansion(expansion), _os(os), + _battlenetRequestToken(0), _warden(NULL), _logoutTime(0), m_inQueue(false), diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index ef6ccf5bf4b..69dbc7bf9e6 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -200,7 +200,7 @@ public: if (zombie) { zombieToBeEatenGUID = zombie->GetGUID(); // save for later use - + // the soon-to-be-eaten zombie should stop moving and stop attacking zombie->AI()->SetData(DATA_ZOMBIE_STATE, STATE_ZOMBIE_TOBE_EATEN); @@ -225,7 +225,7 @@ public: case EVENT_KILL_ZOMBIE_SINGLE: { Creature* zombieToBeEaten = ObjectAccessor::GetCreature(*me, zombieToBeEatenGUID); - if (zombieToBeEaten && zombieToBeEaten->IsAlive() && zombieToBeEaten->IsWithinDistInMap(me, 10.0)) + if (zombieToBeEaten && zombieToBeEaten->IsAlive() && zombieToBeEaten->IsWithinDistInMap(me, 10.0)) DoCast(zombieToBeEaten, SPELL_ZOMBIE_CHOW_SEARCH_SINGLE); // do the killing + healing in done inside by spell script see below. zombieToBeEatenGUID = ObjectGuid::Empty; @@ -249,11 +249,11 @@ public: if (zombie && zombie->IsAlive() && zombie->GetExactDist2d(me) > 18.0) zombie = nullptr; } - + if (zombie) // cast the aoe spell only if at least one zombie is found nearby { Talk(EMOTE_DEVOURS_ALL); - DoCastAOE(SPELL_ZOMBIE_CHOW_SEARCH_MULTI); + DoCastAOE(SPELL_ZOMBIE_CHOW_SEARCH_MULTI); } break; } @@ -269,7 +269,7 @@ public: me->GetMotionMaster()->MoveIdle(); events.ScheduleEvent(EVENT_KILL_ZOMBIE_SINGLE, Seconds(1)); } - + } void DoAction(int32 action) override @@ -405,17 +405,19 @@ public: if (state == STATE_ZOMBIE_DECIMATED) { timer += diff; - Creature* gluth = ObjectAccessor::GetCreature(*me, GluthGUID); // Putting this in the UpdateAI loop fixes an issue where death gripping a decimated zombie would make the zombie stand still until the rest of the fight. // Also fix the issue where if one or more zombie is rooted when decimates hits (and MovePoint() is called), the zombie teleport to the boss. pretty weird behavior. - if (gluth && timer>1600 && me->GetExactDist2d(gluth) > 10.0 && me->CanFreeMove()) // it takes about 1600 ms for the animation to cycle. This way, the animation looks relatively smooth. + if (Creature* gluth = ObjectAccessor::GetCreature(*me, GluthGUID)) { - me->GetMotionMaster()->MovePoint(0, gluth->GetPosition()); // isn't dynamic. So, to take into account Gluth's movement, it must be called periodicly. - timer = 0; - } + if (timer > 1600 && me->GetExactDist2d(gluth) > 10.0 && me->CanFreeMove()) // it takes about 1600 ms for the animation to cycle. This way, the animation looks relatively smooth. + { + me->GetMotionMaster()->MovePoint(0, gluth->GetPosition()); // isn't dynamic. So, to take into account Gluth's movement, it must be called periodicly. + timer = 0; + } - if (me->GetExactDist2d(gluth) <= 10.0) - me->StopMoving(); + if (me->GetExactDist2d(gluth) <= 10.0) + me->StopMoving(); + } } else if (state == STATE_ZOMBIE_NORMAL) DoMeleeAttackIfReady(); @@ -430,10 +432,10 @@ public: { me->SetReactState(ReactStates::REACT_PASSIVE); me->AttackStop(); - me->SetTarget(ObjectGuid::Empty); + me->SetTarget(ObjectGuid::Empty); // at this point, the zombie should be non attacking and non moving. - me->SetWalk(true); // it doesnt seem to work with MoveFollow() (but it does work with MovePoint()). + me->SetWalk(true); // it doesnt seem to work with MoveFollow() (but it does work with MovePoint()). timer = 1000; } -- cgit v1.2.3 From 15bea97f83f655d7c7b8f0db2ee95e08e4f09ceb Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 7 Jun 2016 18:59:11 +0200 Subject: Core/GameObjects: Defined more GO flags (cherry picked from commit 4b00ca02993141a0a5a3e3cf8dea1cde853e9276) --- src/server/game/Miscellaneous/SharedDefines.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index b836611609e..4a69eadb6b1 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -2120,13 +2120,15 @@ enum GameObjectFlags { GO_FLAG_IN_USE = 0x00000001, // disables interaction while animated GO_FLAG_LOCKED = 0x00000002, // require key, spell, event, etc to be opened. Makes "Locked" appear in tooltip - GO_FLAG_INTERACT_COND = 0x00000004, // cannot interact (condition to interact) + GO_FLAG_INTERACT_COND = 0x00000004, // cannot interact (condition to interact - requires GO_DYNFLAG_LO_ACTIVATE to enable interaction clientside) GO_FLAG_TRANSPORT = 0x00000008, // any kind of transport? Object can transport (elevator, boat, car) GO_FLAG_NOT_SELECTABLE = 0x00000010, // not selectable even in GM mode GO_FLAG_NODESPAWN = 0x00000020, // never despawn, typically for doors, they just change state - GO_FLAG_TRIGGERED = 0x00000040, // typically, summoned objects. Triggered by spell or other events + GO_FLAG_AI_OBSTACLE = 0x00000040, // makes the client register the object in something called AIObstacleMgr, unknown what it does + GO_FLAG_FREEZE_ANIMATION = 0x00000080, GO_FLAG_DAMAGED = 0x00000200, - GO_FLAG_DESTROYED = 0x00000400 + GO_FLAG_DESTROYED = 0x00000400, + GO_FLAG_INTERACT_DISTANCE_USES_TEMPLATE_MODEL = 0x00080000, // client checks interaction distance from model sent in SMSG_QUERY_GAMEOBJECT_RESPONSE instead of GAMEOBJECT_DISPLAYID }; enum GameObjectDynamicLowFlags -- cgit v1.2.3 From 7eceba09d79823f015d16cdacc6d9477f7f4cea0 Mon Sep 17 00:00:00 2001 From: Vincent-Michael Date: Wed, 8 Jun 2016 13:05:23 +0200 Subject: Core/Misc: Fixed warnings --- src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 6 +++--- src/server/game/Conditions/ConditionMgr.cpp | 2 +- src/server/scripts/Pet/pet_mage.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index b937f2194e2..9fcb66da1ce 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -443,11 +443,11 @@ void AuctionHouseMgr::PendingAuctionProcess(Player* player) totaldeposit = GetAuctionDeposit(itr->auctionHouseEntry, itr->etime, item, totalItems); uint32 depositremain = totaldeposit; - for (auto itr = thisAH->begin(); itr != thisAH->end(); ++itr) + for (auto itrAH = thisAH->begin(); itrAH != thisAH->end(); ++itrAH) { - AuctionEntry* AH = (*itr); + AuctionEntry* AH = (*itrAH); - if (next(itr) == thisAH->end()) + if (next(itrAH) == thisAH->end()) AH->deposit = depositremain; else { diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 2ff7196a2dc..2f9093a31a5 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -446,7 +446,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const if (Unit* unit = object->ToUnit()) { if (ConditionValue1 == 0) - condMeets = (unit->GetStandState() == ConditionValue2); + condMeets = (unit->GetStandState() == UnitStandStateType(ConditionValue2)); else if (ConditionValue2 == 0) condMeets = unit->IsStandState(); else if (ConditionValue2 == 1) diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp index 9ec779703d3..659a24773b7 100644 --- a/src/server/scripts/Pet/pet_mage.cpp +++ b/src/server/scripts/Pet/pet_mage.cpp @@ -198,8 +198,8 @@ class npc_pet_mage_mirror_image : public CreatureScript if (!target || me->GetVictim() != target) { Unit* ownerTarget = nullptr; - if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) - ownerTarget = owner->GetSelectedUnit(); + if (Player* ownerPlayer = me->GetCharmerOrOwner()->ToPlayer()) + ownerTarget = ownerPlayer->GetSelectedUnit(); // recognize which victim will be choosen if (ownerTarget && ownerTarget->GetTypeId() == TYPEID_PLAYER) -- cgit v1.2.3 From de2efe01055fba7cb254ca5eac211c4c9f390a9b Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 8 Jun 2016 21:46:08 +0200 Subject: Core/Taxi: Implemented PlayerCondition requirements on taxi paths --- src/server/game/Conditions/ConditionMgr.cpp | 4 ++-- src/server/game/Conditions/ConditionMgr.h | 2 +- src/server/game/Entities/Taxi/TaxiPathGraph.cpp | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 2f9093a31a5..76e065f8ddc 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -2368,7 +2368,7 @@ inline bool PlayerConditionLogic(uint32 logic, std::array& results) return result; } -bool ConditionMgr::IsPlayerMeetingCondition(Player* player, PlayerConditionEntry const* condition) +bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* condition) { if (condition->MinLevel && player->getLevel() < condition->MinLevel) return false; @@ -2489,7 +2489,7 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player* player, PlayerConditionEntry if (condition->PartyStatus) { - Group* group = player->GetGroup(); + Group const* group = player->GetGroup(); switch (condition->PartyStatus) { case 1: diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 7c61b4d2955..fb754ab5349 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -271,7 +271,7 @@ class TC_GAME_API ConditionMgr bool IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit* unit, WorldObject* baseObject) const; bool IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player* player, Creature* vendor) const; - static bool IsPlayerMeetingCondition(Player* player, PlayerConditionEntry const* condition); + static bool IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* condition); struct ConditionTypeInfo { diff --git a/src/server/game/Entities/Taxi/TaxiPathGraph.cpp b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp index 6617267be6a..6670c8ea2cb 100644 --- a/src/server/game/Entities/Taxi/TaxiPathGraph.cpp +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp @@ -185,8 +185,9 @@ uint32 TaxiPathGraph::EdgeCost::EvaluateDistance(Player const* player) const if (!(To->Flags & requireFlag)) return std::numeric_limits::max(); - //if (To->ConditionID && !player->MeetsCondition(To->ConditionID)) - // return std::numeric_limits::max(); + if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(To->ConditionID)) + if (!sConditionMgr->IsPlayerMeetingCondition(player, condition)) + return std::numeric_limits::max(); return Distance; } -- cgit v1.2.3 From e744c43a3002a7bf216385a3b3e911449dcf71f2 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 9 Jun 2016 21:55:40 +0200 Subject: Core/Auras: Defined more known stat related aura types --- src/server/game/Spells/Auras/SpellAuraDefines.h | 12 ++++++------ src/server/game/Spells/Auras/SpellAuraEffects.cpp | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 4588b134614..9eb6ad5c864 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -497,10 +497,10 @@ enum AuraType SPELL_AURA_437 = 437, SPELL_AURA_438 = 438, SPELL_AURA_439 = 439, - SPELL_AURA_440 = 440, - SPELL_AURA_441 = 441, - SPELL_AURA_442 = 442, - SPELL_AURA_443 = 443, + SPELL_AURA_MOD_MULTISTRIKE_DAMAGE = 440, // NYI + SPELL_AURA_MOD_MULTISTRIKE_CHANCE = 441, // NYI + SPELL_AURA_MOD_READINESS = 442, // NYI + SPELL_AURA_MOD_LEECH = 443, // NYI SPELL_AURA_444 = 444, SPELL_AURA_445 = 445, SPELL_AURA_446 = 446, @@ -508,7 +508,7 @@ enum AuraType SPELL_AURA_448 = 448, SPELL_AURA_449 = 449, SPELL_AURA_450 = 450, - SPELL_AURA_OVERRIDE_PET_SPECS = 451, // NYI + SPELL_AURA_OVERRIDE_PET_SPECS = 451, SPELL_AURA_452 = 452, SPELL_AURA_CHARGE_RECOVERY_MOD = 453, SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER = 454, @@ -528,7 +528,7 @@ enum AuraType SPELL_AURA_468 = 468, SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY = 469, SPELL_AURA_470 = 470, - SPELL_AURA_471 = 471, + SPELL_AURA_MOD_VERSATILITY = 471, // NYI SPELL_AURA_472 = 472, SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT = 473, // Prevents durability loss from dealing/taking damage SPELL_AURA_474 = 474, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 40db543002b..db1767fa8d4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -499,10 +499,10 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //437 &AuraEffect::HandleNULL, //438 &AuraEffect::HandleNULL, //439 - &AuraEffect::HandleNULL, //440 - &AuraEffect::HandleNULL, //441 - &AuraEffect::HandleNULL, //442 - &AuraEffect::HandleNULL, //443 + &AuraEffect::HandleNULL, //440 SPELL_AURA_MOD_MULTISTRIKE_DAMAGE + &AuraEffect::HandleNULL, //441 SPELL_AURA_MOD_MULTISTRIKE_CHANCE + &AuraEffect::HandleNULL, //442 SPELL_AURA_MOD_READINESS + &AuraEffect::HandleNULL, //443 SPELL_AURA_MOD_LEECH &AuraEffect::HandleNULL, //444 &AuraEffect::HandleNULL, //445 &AuraEffect::HandleNULL, //446 @@ -530,7 +530,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //468 &AuraEffect::HandleShowConfirmationPrompt, //469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY &AuraEffect::HandleNULL, //470 - &AuraEffect::HandleNULL, //471 + &AuraEffect::HandleNULL, //471 SPELL_AURA_MOD_VERSATILITY &AuraEffect::HandleNULL, //472 &AuraEffect::HandleNoImmediateEffect, //473 SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT implemented in Player::DurabilityPointLossForEquipSlot &AuraEffect::HandleNULL, //474 -- cgit v1.2.3 From 051d4036247e196801f40d4cb7826978f970cd99 Mon Sep 17 00:00:00 2001 From: treeston Date: Tue, 31 May 2016 22:49:28 +0200 Subject: Entities/Unit: Fix speed update packets if player is being moved by something else. Closes #17184 Closes #17254 (cherry picked from commit 19fa504ff5a51ded47f516640fc57deb6793547a) --- src/server/game/Entities/Unit/Unit.cpp | 20 +++++++++++++++++--- src/server/game/Entities/Unit/Unit.h | 3 ++- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4328af96d90..c53389d89a2 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10024,20 +10024,20 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate) pet->SetSpeedRate(mtype, m_speed_rate[mtype]); } - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) // unit controlled by a player. { // Send notification to self WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]); selfpacket.MoverGUID = GetGUID(); selfpacket.SequenceIndex = m_movementCounter++; selfpacket.Speed = GetSpeed(mtype); - ToPlayer()->GetSession()->SendPacket(selfpacket.Write()); + playerMover->GetSession()->SendPacket(selfpacket.Write()); // Send notification to other players WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]); packet.movementInfo = &m_movementInfo; packet.Speed = GetSpeed(mtype); - SendMessageToSet(packet.Write(), false); + playerMover->SendMessageToSet(packet.Write(), false); } else { @@ -11610,6 +11610,20 @@ void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state) } } +Unit* Unit::GetMover() const +{ + if (Player const* player = ToPlayer()) + return player->m_mover; + return nullptr; +} + +Player* Unit::GetPlayerMover() const +{ + if (Unit* mover = GetMover()) + return mover->ToPlayer(); + return nullptr; +} + bool Unit::isFrozen() const { return HasAuraState(AURA_STATE_FROZEN); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 415c46afa5d..3a7d25c9ef5 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1751,7 +1751,8 @@ class TC_GAME_API Unit : public WorldObject CharmInfo* InitCharmInfo(); void DeleteCharmInfo(); void UpdateCharmAI(); - //Player* GetMoverSource() const; + Unit* GetMover() const; + Player* GetPlayerMover() const; Player* m_movedPlayer; SharedVisionList const& GetSharedVisionList() { return m_sharedVision; } void AddPlayerToVision(Player* player); -- cgit v1.2.3 From ee2b8b4e87164328e9e7133a6d654f7ac6cd5f8c Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 10 Jun 2016 19:57:49 +0200 Subject: Core/PacketIO: Fixed sending wrong movement packets to nearby players that require ACK response --- src/server/game/Entities/Player/Player.cpp | 8 --- src/server/game/Entities/Player/Player.h | 4 -- src/server/game/Entities/Unit/Unit.cpp | 112 +++++++++++++++++++++-------- src/server/game/Entities/Unit/Unit.h | 1 + 4 files changed, 84 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index da964ef691f..b9ba699b7d0 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -25789,14 +25789,6 @@ void Player::DeleteGarrison() } } -void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) -{ - WorldPackets::Movement::MoveSetFlag packet(apply ? SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY : SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY); - packet.MoverGUID = GetGUID(); - packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); -} - void Player::SendMovementSetCollisionHeight(float height) { WorldPackets::Movement::MoveSetCollisionHeight setCollisionHeight; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 5ff09881eb3..3c630c42fda 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2457,10 +2457,6 @@ class TC_GAME_API Player : public Unit, public GridObject void ValidateMovementInfo(MovementInfo* mi); - /*! These methods send different packets to the client in apply and unapply case. - These methods are only sent to the current unit. - */ - void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply); void SendMovementSetCollisionHeight(float height); bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c53389d89a2..76c91b05df7 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13506,12 +13506,16 @@ void Unit::SetRooted(bool apply, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_ROOT, SMSG_MOVE_ROOT } }; - if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) // unit controlled by a player. { WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -14991,8 +14995,9 @@ void Unit::SendTeleportPacket(Position& pos) WorldPackets::Movement::MoveUpdateTeleport moveUpdateTeleport; moveUpdateTeleport.movementInfo = &m_movementInfo; + Unit* broadcastSource = this; - if (GetTypeId() == TYPEID_PLAYER) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveTeleport moveTeleport; moveTeleport.MoverGUID = GetGUID(); @@ -15002,7 +15007,9 @@ void Unit::SendTeleportPacket(Position& pos) moveTeleport.TransportGUID = GetTransGUID(); moveTeleport.Facing = pos.GetOrientation(); moveTeleport.SequenceIndex = m_movementCounter++; - ToPlayer()->SendDirectMessage(moveTeleport.Write()); + playerMover->SendDirectMessage(moveTeleport.Write()); + + broadcastSource = playerMover; } else { @@ -15014,7 +15021,7 @@ void Unit::SendTeleportPacket(Position& pos) } // Broadcast the packet to everyone except self. - SendMessageToSet(moveUpdateTeleport.Write(), false); + broadcastSource->SendMessageToSet(moveUpdateTeleport.Write(), false); } bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport) @@ -15395,14 +15402,16 @@ bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_DISABLE_GRAVITY, SMSG_MOVE_DISABLE_GRAVITY } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15473,16 +15482,19 @@ bool Unit::SetCanFly(bool enable) { SMSG_MOVE_SPLINE_SET_FLYING, SMSG_MOVE_SET_CAN_FLY } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - if (!enable && player) + if (!enable && GetTypeId() == TYPEID_PLAYER) ToPlayer()->SetFallInformation(0, GetPositionZ()); - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15513,14 +15525,16 @@ bool Unit::SetWaterWalking(bool enable, bool packetOnly /*= false */) { SMSG_MOVE_SPLINE_SET_WATER_WALK, SMSG_MOVE_SET_WATER_WALK } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15551,14 +15565,16 @@ bool Unit::SetFeatherFall(bool enable, bool packetOnly /*= false */) { SMSG_MOVE_SPLINE_SET_FEATHER_FALL, SMSG_MOVE_SET_FEATHER_FALL } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15604,14 +15620,16 @@ bool Unit::SetHover(bool enable, bool packetOnly /*= false*/) { SMSG_MOVE_SPLINE_SET_HOVER, SMSG_MOVE_SET_HOVERING } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15639,14 +15657,16 @@ bool Unit::SetCollision(bool disable) { SMSG_MOVE_SPLINE_DISABLE_COLLISION, SMSG_MOVE_DISABLE_COLLISION } }; - bool player = GetTypeId() == TYPEID_PLAYER && ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER; - - if (player) + if (Player* playerMover = GetPlayerMover()) { WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]); packet.MoverGUID = GetGUID(); packet.SequenceIndex = m_movementCounter++; - SendMessageToSet(packet.Write(), true); + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); } else { @@ -15658,6 +15678,40 @@ bool Unit::SetCollision(bool disable) return true; } +bool Unit::SetCanTransitionBetweenSwimAndFly(bool enable) +{ + if (GetTypeId() != TYPEID_PLAYER) + return false; + + if (enable == HasExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS)) + return false; + + if (enable) + AddExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS); + else + RemoveExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS); + + static OpcodeServer const swimToFlyTransOpcodeTable[2] = + { + SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY, + SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY + }; + + if (Player* playerMover = GetPlayerMover()) + { + WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]); + packet.MoverGUID = GetGUID(); + packet.SequenceIndex = m_movementCounter++; + playerMover->SendDirectMessage(packet.Write()); + + WorldPackets::Movement::MoveUpdate moveUpdate; + moveUpdate.movementInfo = &m_movementInfo; + playerMover->SendMessageToSet(moveUpdate.Write(), false); + } + + return true; +} + void Unit::SendSetVehicleRecId(uint32 vehicleId) { if (Player* player = ToPlayer()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 3a7d25c9ef5..05149a4cd0a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1678,6 +1678,7 @@ class TC_GAME_API Unit : public WorldObject bool SetFeatherFall(bool enable, bool packetOnly = false); bool SetHover(bool enable, bool packetOnly = false); bool SetCollision(bool disable); + bool SetCanTransitionBetweenSwimAndFly(bool enable); void SendSetVehicleRecId(uint32 vehicleId); void SetInFront(WorldObject const* target); -- cgit v1.2.3 From f583476f9ace18a578678c2f8ae7feba9de1a02d Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 11 Jun 2016 00:56:31 +0200 Subject: Core/PacketIO: Send movement status changes around moving unit, not its controller --- src/server/game/Entities/Unit/Unit.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 76c91b05df7..84494f5eff0 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13515,7 +13515,7 @@ void Unit::SetRooted(bool apply, bool packetOnly /*= false*/) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15411,7 +15411,7 @@ bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15494,7 +15494,7 @@ bool Unit::SetCanFly(bool enable) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15534,7 +15534,7 @@ bool Unit::SetWaterWalking(bool enable, bool packetOnly /*= false */) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15574,7 +15574,7 @@ bool Unit::SetFeatherFall(bool enable, bool packetOnly /*= false */) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15629,7 +15629,7 @@ bool Unit::SetHover(bool enable, bool packetOnly /*= false*/) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15666,7 +15666,7 @@ bool Unit::SetCollision(bool disable) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } else { @@ -15706,7 +15706,7 @@ bool Unit::SetCanTransitionBetweenSwimAndFly(bool enable) WorldPackets::Movement::MoveUpdate moveUpdate; moveUpdate.movementInfo = &m_movementInfo; - playerMover->SendMessageToSet(moveUpdate.Write(), false); + SendMessageToSet(moveUpdate.Write(), playerMover); } return true; -- cgit v1.2.3 From c529566ac41e6d14c33015664e43c195a7a36bb6 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 12 Jun 2016 00:11:00 +0200 Subject: Core/GameObejcts: Fixed disconnects happening when viewing nearby players on elevators Closes #17335 --- src/server/game/Battlefield/Battlefield.cpp | 2 +- src/server/game/Battlegrounds/Battleground.cpp | 3 +-- src/server/game/Entities/GameObject/GameObject.cpp | 24 ++++++++++++++-------- src/server/game/Entities/GameObject/GameObject.h | 2 +- src/server/game/Entities/Object/Object.cpp | 2 +- src/server/game/Entities/Object/ObjectGuid.h | 16 +++++++++++++-- src/server/game/Entities/Player/Player.cpp | 2 +- src/server/game/Garrison/Garrison.cpp | 5 ++--- src/server/game/Globals/ObjectAccessor.cpp | 13 ++++++++---- src/server/game/Globals/ObjectAccessor.h | 3 ++- src/server/game/Handlers/MovementHandler.cpp | 2 +- src/server/game/Maps/Map.cpp | 2 ++ src/server/game/Maps/MapScripts.cpp | 8 ++------ src/server/game/Maps/TransportMgr.cpp | 2 +- src/server/game/Maps/ZoneScript.h | 2 +- src/server/game/Spells/SpellEffects.cpp | 18 ++++++---------- src/server/scripts/Commands/cs_gobject.cpp | 14 ++++++------- .../HallsOfReflection/halls_of_reflection.cpp | 4 ++-- .../IcecrownCitadel/instance_icecrown_citadel.cpp | 2 +- .../EyeOfEternity/instance_eye_of_eternity.cpp | 3 +-- src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp | 4 ++-- 21 files changed, 72 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 58874e394e5..0db3ed09ef2 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -828,7 +828,7 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z // Create gameobject GameObject* go = new GameObject; - if (!go->Create(map->GenerateLowGuid(), entry, map, PHASEMASK_NORMAL, x, y, z, o, 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!go->Create(entry, map, PHASEMASK_NORMAL, x, y, z, o, 0, 0, 0, 0, 100, GO_STATE_READY)) { TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Could not create gameobject template %u! Battlefield has not been created!", entry); delete go; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 68a61a28708..e96286692d2 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1461,8 +1461,7 @@ bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created // So we must create it specific for this instance GameObject* go = new GameObject; - if (!go->Create(GetBgMap()->GenerateLowGuid(), entry, GetBgMap(), - PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, goState)) + if (!go->Create(entry, GetBgMap(), PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, goState)) { TC_LOG_ERROR("bg.battleground", "Battleground::AddObject: cannot create gameobject (entry: %u) for BG (map: %u, instance id: %u)!", entry, m_MapId, m_InstanceID); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index a43ab95c80c..ee7241a02d7 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -176,7 +176,7 @@ void GameObject::RemoveFromWorld() } } -bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 /*phaseMask*/, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) +bool GameObject::Create(uint32 name_id, Map* map, uint32 /*phaseMask*/, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) { ASSERT(map); SetMap(map); @@ -185,14 +185,14 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u m_stationaryPosition.Relocate(x, y, z, ang); if (!IsPositionValid()) { - TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, GetSpawnId(), name_id, x, y); + TC_LOG_ERROR("misc", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", GetSpawnId(), name_id, x, y); return false; } SetZoneScript(); if (m_zoneScript) { - name_id = m_zoneScript->GetGameObjectEntry(guidlow, name_id); + name_id = m_zoneScript->GetGameObjectEntry(m_spawnId, name_id); if (!name_id) return false; } @@ -200,26 +200,32 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id); if (!goinfo) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, GetSpawnId(), name_id, map->GetId(), x, y, z); + TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", GetSpawnId(), name_id, map->GetId(), x, y, z); return false; } if (goinfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, GetSpawnId(), name_id); + TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", GetSpawnId(), name_id); return false; } - if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT) + ObjectGuid guid; + if (goinfo->type != GAMEOBJECT_TYPE_TRANSPORT) + guid = ObjectGuid::Create(map->GetId(), goinfo->entry, map->GenerateLowGuid()); + else + { + guid = ObjectGuid::Create(map->GenerateLowGuid()); m_updateFlag |= UPDATEFLAG_TRANSPORT; + } - Object::_Create(ObjectGuid::Create(map->GetId(), goinfo->entry, guidlow)); + Object::_Create(guid); m_goInfo = goinfo; if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, GetSpawnId(), name_id, goinfo->type); + TC_LOG_ERROR("sql.sql", "Gameobject (%s Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guid.ToString().c_str(), GetSpawnId(), name_id, goinfo->type); return false; } @@ -888,7 +894,7 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo uint32 artKit = data->artKit; m_spawnId = spawnId; - if (!Create(map->GenerateLowGuid(), entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) + if (!Create(entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) return false; if (data->phaseid) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index ada26800505..07d1ae7acd6 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -889,7 +889,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject void RemoveFromWorld() override; void CleanupsBeforeDelete(bool finalCleanup = true) override; - bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0); + bool Create(uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0); void Update(uint32 p_time) override; GameObjectTemplate const* GetGOInfo() const { return m_goInfo; } GameObjectData const* GetGOData() const { return m_goData; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index f9fa1b3aeb6..9493df4449c 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2385,7 +2385,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float Map* map = GetMap(); GameObject* go = new GameObject(); - if (!go->Create(map->GenerateLowGuid(), entry, map, GetPhaseMask(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) + if (!go->Create(entry, map, GetPhaseMask(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) { delete go; return NULL; diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 505170a2663..86593a7c211 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -159,7 +159,6 @@ GUID_TRAIT_GLOBAL(HighGuid::CommerceObj) GUID_TRAIT_GLOBAL(HighGuid::ClientSession) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Player) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Item) // This is not exactly correct, there are 2 more unknown parts in highguid: (high >> 10 & 0xFF), (high >> 18 & 0xFFFFFF) -GUID_TRAIT_REALM_SPECIFIC(HighGuid::Transport) GUID_TRAIT_REALM_SPECIFIC(HighGuid::Guild) GUID_TRAIT_MAP_SPECIFIC(HighGuid::WorldTransaction) GUID_TRAIT_MAP_SPECIFIC(HighGuid::Conversation) @@ -181,6 +180,19 @@ GUID_TRAIT_MAP_SPECIFIC(HighGuid::AIResource) GUID_TRAIT_MAP_SPECIFIC(HighGuid::AILock) GUID_TRAIT_MAP_SPECIFIC(HighGuid::AILockTicket) +// Special case +// Global transports are loaded from `transports` table, RealmSpecific part is used for them. +// after worldserver finishes loading, no more global transports can be created, only the ones existing within instances that never change maps +// here is where MapSpecific comes into play - each map takes over the responsibility to generate transport guids +// on top of this, regular elevators (GAMEOBJECT_TYPE_TRANSPORT) must also use Transport highguid type, otherwise client will reject seeing other players on them +template<> +struct ObjectGuidTraits +{ + static bool const Global = false; + static bool const RealmSpecific = true; + static bool const MapSpecific = true; +}; + class ObjectGuid; class PackedGuid; @@ -205,7 +217,7 @@ class TC_GAME_API ObjectGuid static typename std::enable_if::RealmSpecific, ObjectGuid>::type Create(LowType counter) { return RealmSpecific(type, counter); } template - static typename std::enable_if::MapSpecific, ObjectGuid>::type Create(uint16 mapId, uint32 entry, LowType counter) { return MapSpecific(type, 0, mapId, 0, entry, counter); } + static typename std::enable_if::MapSpecific && type != HighGuid::Transport, ObjectGuid>::type Create(uint16 mapId, uint32 entry, LowType counter) { return MapSpecific(type, 0, mapId, 0, entry, counter); } ObjectGuid() : _low(0), _high(0) { } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b9ba699b7d0..4499d5473fb 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22004,7 +22004,7 @@ void Player::UpdateTriggerVisibility() creature->BuildValuesUpdateBlockForPlayer(&udata, this); creature->RemoveFieldNotifyFlag(UF_FLAG_PUBLIC); } - else if (itr->IsGameObject()) + else if (itr->IsAnyTypeGameObject()) { GameObject* go = GetMap()->GetGameObject(*itr); if (!go) diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp index 56cbb9ad58e..5a25f91876e 100644 --- a/src/server/game/Garrison/Garrison.cpp +++ b/src/server/game/Garrison/Garrison.cpp @@ -713,8 +713,7 @@ GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex fact Position const& pos = PacketInfo.PlotPos; GameObject* building = new GameObject(); - if (!building->Create(map->GenerateLowGuid(), entry, map, 0, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), - 0.0f, 0.0f, 0.0f, 0.0f, 255, GO_STATE_READY)) + if (!building->Create(entry, map, 0, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 255, GO_STATE_READY)) { delete building; return nullptr; @@ -726,7 +725,7 @@ GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex fact { Position const& pos2 = finalizeInfo->FactionInfo[faction].Pos; GameObject* finalizer = new GameObject(); - if (finalizer->Create(map->GenerateLowGuid(), finalizeInfo->FactionInfo[faction].GameObjectId, map, 0, pos2.GetPositionX(), pos2.GetPositionY(), + if (finalizer->Create(finalizeInfo->FactionInfo[faction].GameObjectId, map, 0, pos2.GetPositionX(), pos2.GetPositionY(), pos2.GetPositionZ(), pos2.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 255, GO_STATE_READY)) { // set some spell id to make the object delete itself after use diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 7cb21321f04..553cf67cc3c 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -84,12 +84,12 @@ WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid con case HighGuid::Transport: case HighGuid::GameObject: return GetGameObject(p, guid); case HighGuid::Vehicle: - case HighGuid::Creature: return GetCreature(p, guid); + case HighGuid::Creature: return GetCreature(p, guid); case HighGuid::Pet: return GetPet(p, guid); case HighGuid::DynamicObject: return GetDynamicObject(p, guid); case HighGuid::AreaTrigger: return GetAreaTrigger(p, guid); case HighGuid::Corpse: return GetCorpse(p, guid); - default: return NULL; + default: return nullptr; } } @@ -132,7 +132,7 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, ObjectGuid con break; } - return NULL; + return nullptr; } Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, ObjectGuid const& guid) @@ -145,11 +145,16 @@ GameObject* ObjectAccessor::GetGameObject(WorldObject const& u, ObjectGuid const return u.GetMap()->GetGameObject(guid); } -Transport* ObjectAccessor::GetTransport(WorldObject const& u, ObjectGuid const& guid) +Transport* ObjectAccessor::GetTransportOnMap(WorldObject const& u, ObjectGuid const& guid) { return u.GetMap()->GetTransport(guid); } +Transport* ObjectAccessor::GetTransport(ObjectGuid const& guid) +{ + return HashMapHolder::Find(guid); +} + DynamicObject* ObjectAccessor::GetDynamicObject(WorldObject const& u, ObjectGuid const& guid) { return u.GetMap()->GetDynamicObject(guid); diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 83bbdf42239..4ac3b7a79d1 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -72,7 +72,8 @@ namespace ObjectAccessor TC_GAME_API Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask); TC_GAME_API Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid); TC_GAME_API GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid); - TC_GAME_API Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API Transport* GetTransportOnMap(WorldObject const& u, ObjectGuid const& guid); + TC_GAME_API Transport* GetTransport(ObjectGuid const& guid); TC_GAME_API DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid); TC_GAME_API AreaTrigger* GetAreaTrigger(WorldObject const& u, ObjectGuid const& guid); TC_GAME_API Unit* GetUnit(WorldObject const&, ObjectGuid const& guid); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index cace773b65e..6464dd1838a 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -330,7 +330,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) - movementInfo.transport.guid.Clear(); + movementInfo.transport.Reset(); } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 2389d8e0fc1..81aa0fd174c 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -255,6 +255,8 @@ i_scriptLock(false), _defaultLight(GetDefaultMapLight(id)) //lets initialize visibility distance for map Map::InitVisibilityDistance(); + GetGuidSequenceGenerator().Set(sObjectMgr->GetGenerator().GetNextAfterMaxUsed()); + sScriptMgr->OnCreateMap(this); } diff --git a/src/server/game/Maps/MapScripts.cpp b/src/server/game/Maps/MapScripts.cpp index fd1f798d2d0..c60b4d8096d 100644 --- a/src/server/game/Maps/MapScripts.cpp +++ b/src/server/game/Maps/MapScripts.cpp @@ -322,14 +322,12 @@ void Map::ScriptsProcess() source = HashMapHolder::Find(step.sourceGUID); break; case HighGuid::GameObject: + case HighGuid::Transport: source = GetGameObject(step.sourceGUID); break; case HighGuid::Corpse: source = GetCorpse(step.sourceGUID); break; - case HighGuid::Transport: - source = GetTransport(step.sourceGUID); - break; default: TC_LOG_ERROR("scripts", "%s source with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.sourceGUID.ToString().c_str()); @@ -353,14 +351,12 @@ void Map::ScriptsProcess() target = HashMapHolder::Find(step.targetGUID); break; case HighGuid::GameObject: + case HighGuid::Transport: target = GetGameObject(step.targetGUID); break; case HighGuid::Corpse: target = GetCorpse(step.targetGUID); break; - case HighGuid::Transport: - target = GetTransport(step.targetGUID); - break; default: TC_LOG_ERROR("scripts", "%s target with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.targetGUID.ToString().c_str()); diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 5de0133c342..4e695547c42 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -389,7 +389,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid float o = tInfo->keyFrames.begin()->InitialOrientation; // initialize the gameobject base - ObjectGuid::LowType guidLow = guid ? guid : sObjectMgr->GetGenerator().Generate(); + ObjectGuid::LowType guidLow = guid ? guid : ASSERT_NOTNULL(map)->GenerateLowGuid(); if (!trans->Create(guidLow, entry, mapId, x, y, z, o, 255)) { delete trans; diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index e54c96dbb11..e83c6654912 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -30,7 +30,7 @@ class ZoneScript virtual ~ZoneScript() { } virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; } - virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; } + virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*spawnId*/, uint32 entry) { return entry; } virtual void OnCreatureCreate(Creature* ) { } virtual void OnCreatureRemove(Creature* ) { } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 71ab0858534..d9930ce890a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3164,8 +3164,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) Map* map = target->GetMap(); - if (!pGameObj->Create(map->GenerateLowGuid(), gameobject_id, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + if (!pGameObj->Create(gameobject_id, map, m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { delete pGameObj; return; @@ -3191,8 +3190,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) { GameObject* linkedGO = new GameObject; - if (linkedGO->Create(map->GenerateLowGuid(), linkedEntry, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + if (linkedGO->Create(linkedEntry, map, m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { linkedGO->CopyPhaseFrom(m_caster); @@ -3785,8 +3783,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) uint32 gameobject_id = effectInfo->MiscValue; Map* map = m_caster->GetMap(); - if (!pGameObj->Create(map->GenerateLowGuid(), gameobject_id, - map, 0, + if (!pGameObj->Create(gameobject_id, map, 0, m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2, m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2, m_caster->GetPositionZ(), @@ -4154,8 +4151,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE); Map* map = m_caster->GetMap(); - if (!go->Create(map->GenerateLowGuid(), go_id, map, - 0, x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + if (!go->Create(go_id, map, 0, x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) { delete go; return; @@ -4813,8 +4809,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) GameObject* pGameObj = new GameObject; - if (!pGameObj->Create(cMap->GenerateLowGuid(), name_id, cMap, - 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + if (!pGameObj->Create(name_id, cMap, 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { delete pGameObj; return; @@ -4881,8 +4876,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) { GameObject* linkedGO = new GameObject; - if (linkedGO->Create(cMap->GenerateLowGuid(), linkedEntry, cMap, - 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + if (linkedGO->Create(linkedEntry, cMap, 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { linkedGO->CopyPhaseFrom(m_caster); diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 22e9bfe704a..982a15e314d 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -146,9 +146,7 @@ public: Map* map = player->GetMap(); GameObject* object = new GameObject; - ObjectGuid::LowType guidLow = map->GenerateLowGuid(); - - if (!object->Create(guidLow, objectInfo->entry, map, 0, x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + if (!object->Create(objectInfo->entry, map, 0, x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) { delete object; return false; @@ -164,7 +162,7 @@ public: // fill the gameobject data and save to the db object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMask()); - guidLow = object->GetSpawnId(); + ObjectGuid::LowType spawnId = object->GetSpawnId(); // delete the old object and do a clean load from DB with a fresh new GameObject instance. // this is required to avoid weird behavior and memory leaks @@ -172,16 +170,16 @@ public: object = new GameObject(); // this will generate a new guid if the object is in an instance - if (!object->LoadGameObjectFromDB(guidLow, map)) + if (!object->LoadGameObjectFromDB(spawnId, map)) { delete object; return false; } /// @todo is it really necessary to add both the real and DB table guid here ? - sObjectMgr->AddGameobjectToGrid(guidLow, ASSERT_NOTNULL(sObjectMgr->GetGOData(guidLow))); + sObjectMgr->AddGameobjectToGrid(spawnId, ASSERT_NOTNULL(sObjectMgr->GetGOData(spawnId))); - handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), guidLow, x, y, z); + handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), spawnId, x, y, z); return true; } @@ -669,7 +667,7 @@ public: int32 objectState = atoi(state); if (objectType < 4) - object->SetByteValue(GAMEOBJECT_BYTES_1, objectType, objectState); + object->SetByteValue(GAMEOBJECT_BYTES_1, uint8(objectType), uint8(objectState)); else if (objectType == 4) object->SendCustomAnim(objectState); diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 106c567b24e..d755fa15d23 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -1113,7 +1113,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript me->RemoveAurasDueToSpell(SPELL_HARVEST_SOUL); if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) Talk(SAY_JAINA_ESCAPE_9); - if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_GUNSHIP))) + if (Transport* gunship = ObjectAccessor::GetTransportOnMap(*me, _instance->GetGuidData(DATA_GUNSHIP))) gunship->EnableMovement(true); _instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, DONE); break; @@ -1185,7 +1185,7 @@ class npc_the_lich_king_escape_hor : public CreatureScript if (Creature* target = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ESCAPE_LEADER))) DoCast(target, SPELL_HARVEST_SOUL); - if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_GUNSHIP))) + if (Transport* gunship = ObjectAccessor::GetTransportOnMap(*me, _instance->GetGuidData(DATA_GUNSHIP))) gunship->EnableMovement(true); break; default: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 1d6b1ffb61e..7e8ddeda484 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -400,7 +400,7 @@ class instance_icecrown_citadel : public InstanceMapScript return entry; } - uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override + uint32 GetGameObjectEntry(ObjectGuid::LowType /*spawnId*/, uint32 entry) override { switch (entry) { diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index e5944841ad5..f6c829590b9 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -86,8 +86,7 @@ public: void SpawnGameObject(uint32 entry, Position const& pos) { GameObject* go = new GameObject(); - if (!go->Create(instance->GenerateLowGuid(), entry, instance, - PHASEMASK_NORMAL, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), + if (!go->Create(entry, instance, PHASEMASK_NORMAL, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0, 0, 0, 0, 120, GO_STATE_READY)) { delete go; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index 59ff06ea66b..c7f49a67328 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -163,7 +163,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) GameObject* go = new GameObject; Map* map = player->GetMap(); - if (!go->Create(map->GenerateLowGuid(), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!go->Create(SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) { delete go; return true; @@ -194,7 +194,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) GameObject* go = new GameObject; Map* map = player->GetMap(); - if (!go->Create(map->GenerateLowGuid(), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!go->Create(SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) { delete go; return true; -- cgit v1.2.3 From 2fe6fc63d79655a96ee2135a6b380ce353729088 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 13 Jun 2016 18:00:55 +0200 Subject: Core/Movement: Fixed weird loading screen behavior (progress bar loading to full then disappearing) - also makes teleporting between maps faster --- src/server/game/Entities/Player/Player.cpp | 29 +++++++++----------- src/server/game/Handlers/MovementHandler.cpp | 30 ++++++++++++++++++++ src/server/game/Server/Packets/MovementPackets.cpp | 23 ++++++++++++++++ src/server/game/Server/Packets/MovementPackets.h | 32 ++++++++++++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 6 ++-- src/server/game/Server/WorldSession.cpp | 4 --- src/server/game/Server/WorldSession.h | 2 ++ 7 files changed, 103 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 4499d5473fb..1dd3f63097a 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1220,7 +1220,7 @@ void Player::Update(uint32 p_time) m_zoneUpdateTimer -= p_time; } - if (m_timeSyncTimer > 0) + if (m_timeSyncTimer > 0 && !IsBeingTeleportedFar()) { if (p_time >= m_timeSyncTimer) SendTimeSync(); @@ -1635,18 +1635,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { - if (mEntry->IsDungeon()) - { - WorldPackets::Instance::UpdateLastInstance updateLastInstance; - updateLastInstance.MapID = mapid; - SendDirectMessage(updateLastInstance.Write()); - } - - WorldPackets::Movement::NewWorld packet; - packet.MapID = mapid; - packet.Pos = static_cast(m_teleport_dest); - packet.Reason = !(options & TELE_TO_SEAMLESS) ? NEW_WORLD_NORMAL : NEW_WORLD_SEAMLESS; - SendDirectMessage(packet.Write()); + WorldPackets::Movement::SuspendToken suspendToken; + suspendToken.SequenceIndex = m_movementCounter; // not incrementing + suspendToken.Reason = options & TELE_TO_SEAMLESS ? 2 : 1; + SendDirectMessage(suspendToken.Write()); } // move packet sent by client always after far teleport @@ -22222,6 +22214,14 @@ void Player::SetGroup(Group* group, int8 subgroup) void Player::SendInitialPacketsBeforeAddToMap() { + if (!(m_teleport_options & TELE_TO_SEAMLESS)) + { + m_movementCounter = 0; + ResetTimeSync(); + } + + SendTimeSync(); + /// Pass 'this' as argument because we're not stored in ObjectAccessor yet GetSocial()->SendSocialList(this, SOCIAL_FLAG_ALL); @@ -22313,9 +22313,6 @@ void Player::SendInitialPacketsAfterAddToMap() GetZoneAndAreaId(newzone, newarea); UpdateZone(newzone, newarea); // also call SendInitWorldStates(); - ResetTimeSync(); - SendTimeSync(); - GetSession()->SendLoadCUFProfiles(); CastSpell(this, 836, true); // LOGINEFFECT diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 6464dd1838a..d8943099a93 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -31,6 +31,7 @@ #include "InstanceSaveMgr.h" #include "ObjectMgr.h" #include "Vehicle.h" +#include "InstancePackets.h" #include "MovementPackets.h" #define MOVEMENT_PACKET_TIME_DELAY 0 @@ -95,6 +96,11 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->ResetMap(); GetPlayer()->SetMap(newMap); + WorldPackets::Movement::ResumeToken resumeToken; + resumeToken.SequenceIndex = _player->m_movementCounter; + resumeToken.Reason = seamlessTeleport ? 2 : 1; + SendPacket(resumeToken.Write()); + if (!seamlessTeleport) GetPlayer()->SendInitialPacketsBeforeAddToMap(); @@ -214,6 +220,30 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->ProcessDelayedOperations(); } +void WorldSession::HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTokenResponse& /*suspendTokenResponse*/) +{ + if (!_player->IsBeingTeleportedFar()) + return; + + WorldLocation const& loc = GetPlayer()->GetTeleportDest(); + + if (sMapStore.AssertEntry(loc.GetMapId())->IsDungeon()) + { + WorldPackets::Instance::UpdateLastInstance updateLastInstance; + updateLastInstance.MapID = loc.GetMapId(); + SendPacket(updateLastInstance.Write()); + } + + WorldPackets::Movement::NewWorld packet; + packet.MapID = loc.GetMapId(); + packet.Pos.Relocate(loc); + packet.Reason = !_player->IsBeingTeleportedSeamlessly() ? NEW_WORLD_NORMAL : NEW_WORLD_SEAMLESS; + SendPacket(packet.Write()); + + if (_player->IsBeingTeleportedSeamlessly()) + HandleMoveWorldportAckOpcode(); +} + void WorldSession::HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet) { TC_LOG_DEBUG("network", "CMSG_MOVE_TELEPORT_ACK: Guid: %s, Sequence: %u, Time: %u", packet.MoverGUID.ToString().c_str(), packet.AckIndex, packet.MoveTime); diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index 582a057e09f..6fdad7553a3 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -715,3 +715,26 @@ WorldPacket const* WorldPackets::Movement::SummonRequest::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Movement::SuspendToken::Write() +{ + _worldPacket << uint32(SequenceIndex); + _worldPacket.WriteBits(Reason, 2); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Movement::SuspendTokenResponse::Read() +{ + _worldPacket >> SequenceIndex; +} + +WorldPacket const* WorldPackets::Movement::ResumeToken::Write() +{ + _worldPacket << uint32(SequenceIndex); + _worldPacket.WriteBits(Reason, 2); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index 6d97161d9c9..3bce8ed665c 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -461,6 +461,38 @@ namespace WorldPackets int32 AreaID = 0; bool SkipStartingArea = false; }; + + class SuspendToken final : public ServerPacket + { + public: + SuspendToken() : ServerPacket(SMSG_SUSPEND_TOKEN, 4 + 1) { } + + WorldPacket const* Write() override; + + uint32 SequenceIndex = 1; + uint32 Reason = 1; + }; + + class SuspendTokenResponse final : public ClientPacket + { + public: + SuspendTokenResponse(WorldPacket&& packet) : ClientPacket(CMSG_SUSPEND_TOKEN_RESPONSE, std::move(packet)) { } + + void Read() override; + + uint32 SequenceIndex = 0; + }; + + class ResumeToken final : public ServerPacket + { + public: + ResumeToken() : ServerPacket(SMSG_RESUME_TOKEN, 4 + 1) { } + + WorldPacket const* Write() override; + + uint32 SequenceIndex = 1; + uint32 Reason = 1; + }; } ByteBuffer& operator<<(ByteBuffer& data, Movement::MonsterSplineFilterKey const& monsterSplineFilterKey); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7dd7b2dc3e9..a2e4bfe6321 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -732,7 +732,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitComplaint, &WorldSession::HandleSupportTicketSubmitComplaint); DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitSuggestion, &WorldSession::HandleSupportTicketSubmitSuggestion); DEFINE_HANDLER(CMSG_SUSPEND_COMMS_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_TRANSFER, PROCESS_THREADUNSAFE, WorldPackets::Movement::SuspendTokenResponse, &WorldSession::HandleSuspendTokenResponse); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode); DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapItem, &WorldSession::HandleSwapItem); DEFINE_HANDLER(CMSG_SWAP_SUB_GROUPS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SwapSubGroups, &WorldSession::HandleSwapSubGroupsOpcode); @@ -1534,7 +1534,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_CAST_BAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_TOKEN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHANGED_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1641,7 +1641,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TAXI_NODE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEXT_EMOTE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 59f18bc79b0..8e1a912623e 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -336,10 +336,6 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (IsConnectionIdle()) m_Socket[CONNECTION_TYPE_REALM]->CloseSocket(); - if (updater.ProcessUnsafe()) - while (_player && _player->IsBeingTeleportedSeamlessly()) - HandleMoveWorldportAckOpcode(); - ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index b65a8b30d56..26e8329ee9c 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -442,6 +442,7 @@ namespace WorldPackets class MoveTimeSkipped; class SummonResponse; class MoveSplineDone; + class SuspendTokenResponse; } namespace NPC @@ -1243,6 +1244,7 @@ class TC_GAME_API WorldSession void HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortResponse& packet); void HandleMoveWorldportAckOpcode(); // for server-side calls + void HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTokenResponse& suspendTokenResponse); void HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMovement& packet); void HandleSetActiveMoverOpcode(WorldPackets::Movement::SetActiveMover& packet); -- cgit v1.2.3