diff options
Diffstat (limited to 'src')
45 files changed, 1992 insertions, 655 deletions
diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index c9f83cc528d..4ea4f697cf7 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -47,6 +47,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/zmqpp + ${CMAKE_SOURCE_DIR}/dep/process ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Database @@ -58,6 +59,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading + ${CMAKE_SOURCE_DIR}/src/server/shared/Updater ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index 5f4f63287e5..678e24c4682 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -36,6 +36,7 @@ #include "SystemConfig.h" #include "Util.h" #include "ZmqContext.h" +#include "DatabaseLoader.h" #include <cstdlib> #include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> @@ -162,32 +163,13 @@ bool StartDB() { MySQL::Library_Init(); - std::string dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); - if (dbstring.empty()) - { - TC_LOG_ERROR("server.bnetserver", "Database not specified"); - return false; - } - - int32 worker_threads = sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1); - if (worker_threads < 1 || worker_threads > 32) - { - TC_LOG_ERROR("server.bnetserver", "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1."); - worker_threads = 1; - } + // Load databases + DatabaseLoader loader("server.bnetserver", DatabaseLoader::DATABASE_NONE); + loader + .AddDatabase(LoginDatabase, "Login"); - int32 synch_threads = sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1); - if (synch_threads < 1 || synch_threads > 32) - { - TC_LOG_ERROR("server.bnetserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1."); - synch_threads = 1; - } - - if (!LoginDatabase.Open(dbstring, uint8(worker_threads), uint8(synch_threads))) - { - TC_LOG_ERROR("server.bnetserver", "Cannot connect to database"); + if (!loader.Load()) return false; - } TC_LOG_INFO("server.bnetserver", "Started auth database connection pool."); sLog->SetRealmId(0); // Enables DB appenders when realm is set. diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 462bb0cd075..804ce51ef2a 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -9,6 +9,7 @@ # EXAMPLE CONFIG # AUTH SERVER SETTINGS # MYSQL SETTINGS +# UPDATE SETTINGS # LOGGING SYSTEM SETTINGS # ################################################################################################### @@ -165,6 +166,86 @@ Wrong.Password.Login.Logging = 0 ################################################################################################### ################################################################################################### +# UPDATE SETTINGS +# +# Updates.EnableDatabases +# Description: A mask that describes which databases shall be updated. +# +# Following flags are available +# DATABASE_LOGIN = 1, // Auth database +# +# Default: 0 - (All Disabled) +# 1 - (All Enabled) + +Updates.EnableDatabases = 0 + +# +# Updates.SourcePath +# Description: The path to your TrinityCore source directory. +# If the path is left empty, built-in CMAKE_SOURCE_DIR is used. +# Example: "../TrinityCore" +# Default: "" + +Updates.SourcePath = "" + +# +# Updates.SourcePath +# Description: The path to your mysql cli binary. +# If the path is left empty, built-in path from cmake is used. +# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" +# "mysql.exe" +# "/usr/bin/mysql" +# Default: "" + +Updates.MySqlCLIPath = "" + +# +# Updates.AutoSetup +# Description: Auto populate empty databases. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.AutoSetup = 1 + +# +# Updates.Redundancy +# Description: Perform data redundancy checks through hashing +# to detect changes on sql updates and reapply it. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.Redundancy = 1 + +# +# Updates.ArchivedRedundancy +# Description: Check hashes of archived updates (slows down startup). +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Updates.ArchivedRedundancy = 0 + +# +# Updates.AllowRehash +# Description: Inserts the current file hash in the database if it is left empty. +# Useful if you want to mark a file as applied but you don't know its hash. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.AllowRehash = 1 + +# +# Updates.CleanDeadRef +# Description: Cleans dead/ orphaned references that occure if a update was deleted or renamed and edited. +# Disable this if you want to know if the database is in a possible "dirty state". +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.CleanDeadRef = 1 + +# +################################################################################################### + +################################################################################################### # # LOGGING SYSTEM SETTINGS # @@ -255,6 +336,7 @@ Logger.root=3,Console Bnet Logger.realmlist=3,Console Bnet Logger.session=3,Console Bnet Logger.session.packets=3,Console Bnet +Logger.sql.updates=3,Console Bnet # ################################################################################################### diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index ab54efab1fd..55792856eb4 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -131,6 +131,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading + ${CMAKE_SOURCE_DIR}/src/server/shared/Updater ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index d5d53df48c1..42b19771387 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -470,6 +470,7 @@ struct GameObjectTemplate { uint32 chairheight; // 0 chairheight, int, Min value: 0, Max value: 2, Default value: 1 int32 HeightOffset; // 1 Height Offset (inches), int, Min value: -100, Max value: 100, Default value: 0 + uint32 SitAnimKit; // 2 Sit Anim Kit, References: AnimKit, NoValue = 0 } barberChair; // 33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING struct @@ -587,6 +588,8 @@ struct GameObjectTemplate { int32 mapID; // 0 mapID, References: Map, NoValue = -1 int32 namedset; // 1 named set, int, Min value: -2147483648, Max value: 2147483647, Default value: 0 + uint32 Primarydoodadset; // 2 Primary doodad set, int, Min value: -2147483648, Max value: 2147483647, Default value: 0 + uint32 Secondarydoodadset; // 3 Secondary doodad set, int, Min value: -2147483648, Max value: 2147483647, Default value: 0 } phaseableMO; // 44 GAMEOBJECT_TYPE_GARRISON_MONUMENT struct diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6ea9bc523b9..0f5a36e14b4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -23691,28 +23691,9 @@ void Player::SetMover(Unit* target) m_mover = target; m_mover->m_movedPlayer = this; - ObjectGuid guid = target->GetGUID(); - - WorldPacket data(SMSG_MOVE_SET_ACTIVE_MOVER, 9); - data.WriteBit(guid[5]); - data.WriteBit(guid[7]); - data.WriteBit(guid[3]); - data.WriteBit(guid[6]); - data.WriteBit(guid[0]); - data.WriteBit(guid[4]); - data.WriteBit(guid[1]); - data.WriteBit(guid[2]); - - data.WriteByteSeq(guid[6]); - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[0]); - data.WriteByteSeq(guid[5]); - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[1]); - data.WriteByteSeq(guid[4]); - - SendDirectMessage(&data); + WorldPackets::Movement::MoveSetActiveMover packet; + packet.MoverGUID = target->GetGUID(); + SendDirectMessage(packet.Write()); } void Player::UpdateZoneDependentAuras(uint32 newZone) diff --git a/src/server/game/Handlers/BankHandler.cpp b/src/server/game/Handlers/BankHandler.cpp new file mode 100644 index 00000000000..8879b4e2532 --- /dev/null +++ b/src/server/game/Handlers/BankHandler.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BankPackets.h" +#include "NPCPackets.h" +#include "ObjectMgr.h" +#include "Opcodes.h" +#include "Player.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +void WorldSession::HandleAutoBankItemOpcode(WorldPackets::Bank::AutoBankItem& packet) +{ + TC_LOG_DEBUG("network", "STORAGE: receive bag = %u, slot = %u", packet.Bag, packet.Slot); + + if (!CanUseBank()) + { + TC_LOG_ERROR("network", "WORLD: HandleAutoBankItemOpcode - Unit (%s) not found or you can't interact with him.", m_currentBankerGUID.ToString().c_str()); + return; + } + + Item* item = _player->GetItemByPos(packet.Bag, packet.Slot); + if (!item) + return; + + ItemPosCountVec dest; + InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, item, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, item, NULL); + return; + } + + if (dest.size() == 1 && dest[0].pos == item->GetPos()) + { + _player->SendEquipError(EQUIP_ERR_CANT_SWAP, item, NULL); + return; + } + + _player->RemoveItem(packet.Bag, packet.Slot, true); + _player->ItemRemovedQuestCheck(item->GetEntry(), item->GetCount()); + _player->BankItem(dest, item, true); +} + +void WorldSession::HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet) +{ + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_BANKER); + if (!unit) + { + TC_LOG_ERROR("network", "WORLD: HandleBankerActivateOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // set currentBankerGUID for other bank action + + SendShowBank(packet.Unit); +} + +void WorldSession::HandleAutoStoreBankItemOpcode(WorldPackets::Bank::AutoStoreBankItem& packet) +{ + TC_LOG_DEBUG("network", "STORAGE: receive bag = %u, slot = %u", packet.Bag, packet.Slot); + + if (!CanUseBank()) + { + TC_LOG_ERROR("network", "WORLD: HandleAutoStoreBankItemOpcode - Unit (%s) not found or you can't interact with him.", m_currentBankerGUID.ToString().c_str()); + return; + } + + Item* item = _player->GetItemByPos(packet.Bag, packet.Slot); + if (!item) + return; + + if (_player->IsBankPos(packet.Bag, packet.Slot)) // moving from bank to inventory + { + ItemPosCountVec dest; + InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, item, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, item, NULL); + return; + } + + _player->RemoveItem(packet.Bag, packet.Slot, true); + if (Item const* storedItem = _player->StoreItem(dest, item, true)) + _player->ItemAddedQuestCheck(storedItem->GetEntry(), storedItem->GetCount()); + + } + else // moving from inventory to bank + { + ItemPosCountVec dest; + InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, item, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, item, NULL); + return; + } + + _player->RemoveItem(packet.Bag, packet.Slot, true); + _player->BankItem(dest, item, true); + } +} + +void WorldSession::HandleBuyBankSlotOpcode(WorldPackets::Bank::BuyBankSlot& packet) +{ + WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); + if (!CanUseBank(packet.Guid)) + { + data << uint32(ERR_BANKSLOT_NOTBANKER); + SendPacket(&data); + TC_LOG_ERROR("network", "WORLD: HandleBuyBankSlotOpcode - %s not found or you can't interact with him.", packet.Guid.ToString().c_str()); + return; + } + + uint32 slot = _player->GetBankBagSlotCount(); + + // next slot + ++slot; + + TC_LOG_INFO("network", "PLAYER: Buy bank bag slot, slot number = %u", slot); + + BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); + + if (!slotEntry) + { + data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); + SendPacket(&data); + return; + } + + uint32 price = slotEntry->Cost; + + if (!_player->HasEnoughMoney(uint64(price))) + { + data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); + SendPacket(&data); + return; + } + + _player->SetBankBagSlotCount(slot); + _player->ModifyMoney(-int64(price)); + + data << uint32(ERR_BANKSLOT_OK); + SendPacket(&data); + + _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); +} + +void WorldSession::SendShowBank(ObjectGuid guid) +{ + m_currentBankerGUID = guid; + WorldPackets::NPC::ShowBank packet; + packet.Guid = guid; + SendPacket(packet.Write()); +} diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index e6803832a56..db7b49521c3 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -741,140 +741,6 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBag _player->StoreItem(dest, item, true); } -void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) -{ - TC_LOG_DEBUG("network", "WORLD: CMSG_BUY_BANK_SLOT"); - - ObjectGuid guid; - recvPacket >> guid; - - WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); - if (!CanUseBank(guid)) - { - data << uint32(ERR_BANKSLOT_NOTBANKER); - SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: HandleBuyBankSlotOpcode - %s not found or you can't interact with him.", guid.ToString().c_str()); - return; - } - - uint32 slot = _player->GetBankBagSlotCount(); - - // next slot - ++slot; - - TC_LOG_INFO("network", "PLAYER: Buy bank bag slot, slot number = %u", slot); - - BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); - - if (!slotEntry) - { - data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); - SendPacket(&data); - return; - } - - uint32 price = slotEntry->Cost; - - if (!_player->HasEnoughMoney(uint64(price))) - { - data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); - SendPacket(&data); - return; - } - - _player->SetBankBagSlotCount(slot); - _player->ModifyMoney(-int64(price)); - - data << uint32(ERR_BANKSLOT_OK); - SendPacket(&data); - - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); -} - -void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) -{ - TC_LOG_DEBUG("network", "WORLD: CMSG_AUTOBANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - if (!CanUseBank()) - { - TC_LOG_DEBUG("network", "WORLD: HandleAutoBankItemOpcode - Unit (%s) not found or you can't interact with him.", m_currentBankerGUID.ToString().c_str()); - return; - } - - Item* pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - ItemPosCountVec dest; - InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - if (dest.size() == 1 && dest[0].pos == pItem->GetPos()) - { - _player->SendEquipError(EQUIP_ERR_CANT_SWAP, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->BankItem(dest, pItem, true); -} - -void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) -{ - TC_LOG_DEBUG("network", "WORLD: CMSG_AUTOSTORE_BANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - if (!CanUseBank()) - { - TC_LOG_DEBUG("network", "WORLD: HandleAutoStoreBankItemOpcode - Unit (%s) not found or you can't interact with him.", m_currentBankerGUID.ToString().c_str()); - return; - } - - Item* pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory - { - ItemPosCountVec dest; - InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - if (Item const* storedItem = _player->StoreItem(dest, pItem, true)) - _player->ItemAddedQuestCheck(storedItem->GetEntry(), storedItem->GetCount()); - } - else // moving from inventory to bank - { - ItemPosCountVec dest; - InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->BankItem(dest, pItem, true); - } -} - void WorldSession::SendEnchantmentLog(ObjectGuid target, ObjectGuid caster, uint32 itemId, uint32 enchantId) { WorldPacket data(SMSG_ENCHANTMENT_LOG, (8+8+4+4)); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index d1f4c862b0c..f40527b66d7 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -465,33 +465,13 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPackets::Movement::MovementSpe } } -void WorldSession::HandleSetActiveMoverOpcode(WorldPacket& recvPacket) +void WorldSession::HandleSetActiveMoverOpcode(WorldPackets::Movement::SetActiveMover& packet) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); - ObjectGuid guid; - - guid[7] = recvPacket.ReadBit(); - guid[2] = recvPacket.ReadBit(); - guid[1] = recvPacket.ReadBit(); - guid[0] = recvPacket.ReadBit(); - guid[4] = recvPacket.ReadBit(); - guid[5] = recvPacket.ReadBit(); - guid[6] = recvPacket.ReadBit(); - guid[3] = recvPacket.ReadBit(); - - recvPacket.ReadByteSeq(guid[3]); - recvPacket.ReadByteSeq(guid[2]); - recvPacket.ReadByteSeq(guid[4]); - recvPacket.ReadByteSeq(guid[0]); - recvPacket.ReadByteSeq(guid[5]); - recvPacket.ReadByteSeq(guid[1]); - recvPacket.ReadByteSeq(guid[6]); - recvPacket.ReadByteSeq(guid[7]); - if (GetPlayer()->IsInWorld()) - if (_player->m_mover->GetGUID() != guid) - TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s" , guid.ToString().c_str(), _player->m_mover->GetGUID().ToString().c_str()); + if (_player->m_mover->GetGUID() != packet.ActiveMover) + TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s" , packet.ActiveMover.ToString().c_str(), _player->m_mover->GetGUID().ToString().c_str()); } void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData) diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 80a2284aa7d..48e752b5d0b 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -73,31 +73,6 @@ void WorldSession::SendTabardVendorActivate(ObjectGuid guid) SendPacket(packet.Write()); } -void WorldSession::HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet) -{ - TC_LOG_DEBUG("network", "WORLD: Received CMSG_BANKER_ACTIVATE"); - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_BANKER); - if (!unit) - { - TC_LOG_DEBUG("network", "WORLD: HandleBankerActivateOpcode - %s not found or you can not interact with him.", packet.Unit.ToString().c_str()); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendShowBank(packet.Unit); -} - -void WorldSession::SendShowBank(ObjectGuid guid) -{ - WorldPackets::NPC::ShowBank packet; - packet.Guid = guid; - SendPacket(packet.Write()); -} - void WorldSession::SendShowMailBox(ObjectGuid guid) { WorldPacket data(SMSG_SHOW_MAILBOX, 8); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 5142eebbaa2..0f01ba2dfae 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1252,7 +1252,13 @@ enum SpellEffectName SPELL_EFFECT_242 = 242, SPELL_EFFECT_243 = 243, SPELL_EFFECT_244 = 244, - TOTAL_SPELL_EFFECTS = 245, + SPELL_EFFECT_245 = 245, + SPELL_EFFECT_246 = 246, + SPELL_EFFECT_247 = 247, + SPELL_EFFECT_248 = 248, + SPELL_EFFECT_249 = 249, + SPELL_EFFECT_250 = 250, + TOTAL_SPELL_EFFECTS = 251, }; enum SpellCastResult // 19702 @@ -1984,6 +1990,26 @@ enum Targets TARGET_UNK_125 = 125, TARGET_UNK_126 = 126, TARGET_UNK_127 = 127, + TARGET_UNK_128 = 128, + TARGET_UNK_129 = 129, + TARGET_UNK_130 = 130, + TARGET_UNK_131 = 131, + TARGET_UNK_132 = 132, + TARGET_UNK_133 = 133, + TARGET_UNK_134 = 134, + TARGET_UNK_135 = 135, + TARGET_UNK_136 = 136, + TARGET_UNK_137 = 137, + TARGET_UNK_138 = 138, + TARGET_UNK_139 = 139, + TARGET_UNK_140 = 140, + TARGET_UNK_141 = 141, + TARGET_UNK_142 = 142, + TARGET_UNK_143 = 143, + TARGET_UNK_144 = 144, + TARGET_UNK_145 = 145, + TARGET_UNK_146 = 146, + TARGET_UNK_147 = 147, TOTAL_SPELL_TARGETS }; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 603089b0a6b..553c752ccce 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -368,7 +368,6 @@ void AddSC_dustwallow_marsh(); void AddSC_felwood(); void AddSC_feralas(); void AddSC_moonglade(); -void AddSC_mulgore(); void AddSC_orgrimmar(); void AddSC_silithus(); void AddSC_stonetalon_mountains(); @@ -1090,7 +1089,6 @@ void AddKalimdorScripts() AddSC_felwood(); AddSC_feralas(); AddSC_moonglade(); - AddSC_mulgore(); AddSC_orgrimmar(); AddSC_silithus(); AddSC_stonetalon_mountains(); diff --git a/src/server/game/Server/Packets/BankPackets.cpp b/src/server/game/Server/Packets/BankPackets.cpp new file mode 100644 index 00000000000..0f6af30bed0 --- /dev/null +++ b/src/server/game/Server/Packets/BankPackets.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BankPackets.h" +#include "ItemPackets.h" + +void WorldPackets::Bank::AutoBankItem::Read() +{ + _worldPacket >> Inv + >> Bag + >> Slot; +} + +void WorldPackets::Bank::AutoStoreBankItem::Read() +{ + _worldPacket >> Inv + >> Bag + >> Slot; +} + +void WorldPackets::Bank::BuyBankSlot::Read() +{ + _worldPacket >> Guid; +} diff --git a/src/server/game/Server/Packets/BankPackets.h b/src/server/game/Server/Packets/BankPackets.h new file mode 100644 index 00000000000..dc7883c3643 --- /dev/null +++ b/src/server/game/Server/Packets/BankPackets.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BankPackets_h__ +#define BankPackets_h__ + +#include "ItemPackets.h" +#include "Packet.h" +#include "ObjectGuid.h" +#include "WorldSession.h" + +namespace WorldPackets +{ + namespace Bank + { + class AutoBankItem final : public ClientPacket + { + public: + AutoBankItem(WorldPacket&& packet) : ClientPacket(CMSG_AUTOBANK_ITEM, std::move(packet)) { } + + void Read() override; + + WorldPackets::Item::InvUpdate Inv; + uint8 Bag = 0; + uint8 Slot = 0; + }; + + class AutoStoreBankItem final : public ClientPacket + { + public: + AutoStoreBankItem(WorldPacket&& packet) : ClientPacket(CMSG_AUTOSTORE_BANK_ITEM, std::move(packet)) { } + + void Read() override; + + WorldPackets::Item::InvUpdate Inv; + uint8 Bag = 0; + uint8 Slot = 0; + }; + + class BuyBankSlot final : public ClientPacket + { + public: + BuyBankSlot(WorldPacket&& packet) : ClientPacket(CMSG_BUY_BANK_SLOT, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + }; + } +} +#endif // BankPackets_h__ diff --git a/src/server/game/Server/Packets/MailPackets.cpp b/src/server/game/Server/Packets/MailPackets.cpp index d558b4682c1..425feac5d9f 100644 --- a/src/server/game/Server/Packets/MailPackets.cpp +++ b/src/server/game/Server/Packets/MailPackets.cpp @@ -240,8 +240,6 @@ WorldPackets::Mail::MailQueryNextTimeResult::MailNextTimeEntry::MailNextTimeEntr { case MAIL_NORMAL: SenderGuid = ObjectGuid::Create<HighGuid::Player>(mail->sender); - SenderHint.NativeRealmAddress.Set(GetVirtualRealmAddress()); - SenderHint.VirtualRealmAddress.Set(GetVirtualRealmAddress()); break; case MAIL_AUCTION: case MAIL_CREATURE: @@ -264,8 +262,6 @@ WorldPacket const* WorldPackets::Mail::MailQueryNextTimeResult::Write() for (auto const& entry : Next) { _worldPacket << entry.SenderGuid; - _worldPacket << entry.SenderHint; - _worldPacket << float(entry.TimeLeft); _worldPacket << int32(entry.AltSenderID); _worldPacket << int8(entry.AltSenderType); diff --git a/src/server/game/Server/Packets/MailPackets.h b/src/server/game/Server/Packets/MailPackets.h index 281a48b7248..e79469a76d8 100644 --- a/src/server/game/Server/Packets/MailPackets.h +++ b/src/server/game/Server/Packets/MailPackets.h @@ -223,7 +223,6 @@ namespace WorldPackets MailNextTimeEntry(::Mail const* mail); ObjectGuid SenderGuid; - Query::PlayerGuidLookupHint SenderHint; float TimeLeft = 0.0f; int32 AltSenderID = 0; int8 AltSenderType = 0; diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index d0a3e0038e9..836c00b70ca 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -608,3 +608,15 @@ void WorldPackets::Movement::MovementSpeedAck::Read() _worldPacket >> AckIndex; _worldPacket >> Speed; } + +void WorldPackets::Movement::SetActiveMover::Read() +{ + _worldPacket >> ActiveMover; +} + +WorldPacket const* WorldPackets::Movement::MoveSetActiveMover::Write() +{ + _worldPacket << MoverGUID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index 0e5449c7947..0b57cdaddb0 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -308,6 +308,26 @@ namespace WorldPackets int32 AckIndex = 0; float Speed = 0.0f; }; + + class SetActiveMover final : public ClientPacket + { + public: + SetActiveMover(WorldPacket&& packet) : ClientPacket(CMSG_SET_ACTIVE_MOVER, std::move(packet)) { } + + void Read() override; + + ObjectGuid ActiveMover; + }; + + class MoveSetActiveMover final : public ServerPacket + { + public: + MoveSetActiveMover() : ServerPacket(SMSG_MOVE_SET_ACTIVE_MOVER, 8) { } + + WorldPacket const* Write() override; + + ObjectGuid MoverGUID; + }; } 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 bb6d69260bc..467e56fb1f1 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -20,6 +20,7 @@ #include "WorldSession.h" #include "Packets/AchievementPackets.h" #include "Packets/AuctionHousePackets.h" +#include "Packets/BankPackets.h" #include "Packets/BlackMarketPackets.h" #include "Packets/CharacterPackets.h" #include "Packets/ChannelPackets.h" @@ -178,12 +179,12 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_SELL_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem ); DEFINE_HANDLER(CMSG_AUTH_CONTINUED_SESSION, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_AUTH_SESSION, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); - DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOBANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode ); + DEFINE_HANDLER(CMSG_AUTOBANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Bank::AutoBankItem, &WorldSession::HandleAutoBankItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOEQUIP_GROUND_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_HANDLER(CMSG_AUTOEQUIP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Item::AutoEquipItem, &WorldSession::HandleAutoEquipItemOpcode); + DEFINE_HANDLER(CMSG_AUTOEQUIP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::AutoEquipItem, &WorldSession::HandleAutoEquipItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOEQUIP_ITEM_SLOT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemSlotOpcode ); DEFINE_HANDLER(CMSG_AUTOSTORE_BAG_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Item::AutoStoreBagItem, &WorldSession::HandleAutoStoreBagItemOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_BANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); + DEFINE_HANDLER(CMSG_AUTOSTORE_BANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Bank::AutoStoreBankItem, &WorldSession::HandleAutoStoreBankItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_GROUND_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Loot::AutoStoreLootItem, &WorldSession::HandleAutostoreLootItemOpcode); DEFINE_HANDLER(CMSG_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleBankerActivateOpcode); @@ -228,7 +229,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_BUG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBugReportOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BUSY_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBusyTradeOpcode ); DEFINE_HANDLER(CMSG_BUY_BACK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::BuyBackItem, &WorldSession::HandleBuybackItem); - DEFINE_OPCODE_HANDLER_OLD(CMSG_BUY_BANK_SLOT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyBankSlotOpcode ); + DEFINE_HANDLER(CMSG_BUY_BANK_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Bank::BuyBankSlot, &WorldSession::HandleBuyBankSlotOpcode); DEFINE_HANDLER(CMSG_BUY_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::BuyItem, &WorldSession::HandleBuyItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_CAGE_BATTLE_PET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_CALENDAR_ADD_EVENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarAddEvent ); @@ -488,7 +489,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_LF_GUILD_SET_GUILD_POST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderSetGuildPost ); DEFINE_HANDLER(CMSG_LIST_INVENTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleListInventoryOpcode); DEFINE_HANDLER(CMSG_LOAD_SCREEN, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::LoadingScreenNotify, &WorldSession::HandleLoadScreenOpcode); - DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Character::LogoutCancel, &WorldSession::HandleLogoutCancelOpcode); + DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::LogoutCancel, &WorldSession::HandleLogoutCancelOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_LOGOUT_INSTANT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::LogoutRequest, &WorldSession::HandleLogoutRequestOpcode); DEFINE_HANDLER(CMSG_LOG_DISCONNECT, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); @@ -600,7 +601,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_TOGGLE_COLLISION_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_TOGGLE_COLLISION_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_WATER_WALK_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveWaterWalkAck ); - DEFINE_HANDLER(CMSG_MOVE_WORLDPORT_ACK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Movement::WorldPortAck, &WorldSession::HandleMoveWorldportAckOpcode); + DEFINE_HANDLER(CMSG_MOVE_WORLDPORT_ACK, STATUS_TRANSFER, PROCESS_THREADUNSAFE, WorldPackets::Movement::WorldPortAck, &WorldSession::HandleMoveWorldportAckOpcode); DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::QueryPlayerName, &WorldSession::HandleNameQueryOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_NEUTRAL_PLAYER_SELECT_FACTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_NEW_SPELL_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -667,7 +668,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_QUESTGIVER_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverHello, &WorldSession::HandleQuestgiverHelloOpcode); DEFINE_HANDLER(CMSG_QUESTGIVER_QUERY_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverQueryQuest, &WorldSession::HandleQuestgiverQueryQuestOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_QUEST_AUTOLAUNCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_HANDLER(CMSG_QUESTGIVER_REQUEST_REWARD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverRequestReward, &WorldSession::HandleQuestgiverRequestRewardOpcode); + DEFINE_HANDLER(CMSG_QUESTGIVER_REQUEST_REWARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverRequestReward, &WorldSession::HandleQuestgiverRequestRewardOpcode); DEFINE_HANDLER(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverStatusMultipleQuery, &WorldSession::HandleQuestgiverStatusMultipleQuery); DEFINE_HANDLER(CMSG_QUESTGIVER_STATUS_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Quest::QuestGiverStatusQuery, &WorldSession::HandleQuestgiverStatusQueryOpcode); DEFINE_HANDLER(CMSG_QUESTLOG_REMOVE_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestLogRemoveQuest, &WorldSession::HandleQuestLogRemoveQuest); @@ -691,7 +692,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REPAIR_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::RepairItem, &WorldSession::HandleRepairItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPLACE_ACCOUNT_DATA, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPLACE_TROPHY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_HANDLER(CMSG_REPOP_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Misc::RepopRequest, &WorldSession::HandleRepopRequest); + DEFINE_HANDLER(CMSG_REPOP_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::RepopRequest, &WorldSession::HandleRepopRequest); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPORT_FILTERED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPORT_IGNORED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPORT_PVP_AFK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReportPvPAFK ); @@ -742,7 +743,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACHIEVEMENTS_HIDDEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SET_ACTIONBAR_TOGGLES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetActionBarToggles, &WorldSession::HandleSetActionBarToggles); DEFINE_HANDLER(CMSG_SET_ACTION_BUTTON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::SetActionButton, &WorldSession::HandleSetActionButtonOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_MOVER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveMoverOpcode ); + DEFINE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Movement::SetActiveMover, &WorldSession::HandleSetActiveMoverOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ADVANCED_COMBAT_LOGGING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ASSISTANT_LEADER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupAssistantLeaderOpcode); @@ -808,7 +809,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_COMMS_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode); - DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapItem, &WorldSession::HandleSwapItem); + DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapItem, &WorldSession::HandleSwapItem); DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_SUB_GROUPS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSwapSubGroupOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SYNC_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_TABARD_VENDOR_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTabardVendorActivateOpcode); @@ -835,6 +836,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Petition::TurnInPetition, &WorldSession::HandleTurnInPetition); DEFINE_HANDLER(CMSG_TUTORIAL_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::TutorialSetFlag, &WorldSession::HandleTutorialFlag); DEFINE_HANDLER(CMSG_UI_TIME_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::UITimeRequest, &WorldSession::HandleUITimeRequest); + DEFINE_OPCODE_HANDLER_OLD(CMSG_TWITTER_GET_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNACCEPT_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode ); DEFINE_HANDLER(CMSG_UNDELETE_CHARACTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Character::UndeleteCharacter, &WorldSession::HandleCharUndeleteOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_UNLEARN_SKILL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode ); @@ -1445,7 +1447,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_KNOCK_BACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_REMOVE_MOVEMENT_FORCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ROOT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_ACTIVE_MOVER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_ACTIVE_MOVER, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_FLY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index e1b459c2599..819fe08ead7 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -73,21 +73,21 @@ enum OpcodeClient : uint32 CMSG_ATTACKSWING = 0x048B, CMSG_AUCTION_HELLO_REQUEST = 0x06E3, CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x0C81, - CMSG_AUCTION_LIST_ITEMS = 0xBADD, + CMSG_AUCTION_LIST_ITEMS = 0x05C3, CMSG_AUCTION_LIST_OWNER_ITEMS = 0x082A, CMSG_AUCTION_LIST_PENDING_SALES = 0x0D82, CMSG_AUCTION_PLACE_BID = 0x09E1, - CMSG_AUCTION_REMOVE_ITEM = 0xBADD, + CMSG_AUCTION_REMOVE_ITEM = 0x1309, CMSG_AUCTION_REPLICATE_ITEMS = 0xBADD, - CMSG_AUCTION_SELL_ITEM = 0xBADD, + CMSG_AUCTION_SELL_ITEM = 0x09A3, CMSG_AUTH_CONTINUED_SESSION = 0x1A72, CMSG_AUTH_SESSION = 0x1872, - CMSG_AUTOBANK_ITEM = 0xBADD, + CMSG_AUTOBANK_ITEM = 0x00C6, CMSG_AUTOEQUIP_GROUND_ITEM = 0xBADD, - CMSG_AUTOEQUIP_ITEM = 0xBADD, - CMSG_AUTOEQUIP_ITEM_SLOT = 0xBADD, + CMSG_AUTOEQUIP_ITEM = 0x0235, + CMSG_AUTOEQUIP_ITEM_SLOT = 0x00E5, CMSG_AUTOSTORE_BAG_ITEM = 0xBADD, - CMSG_AUTOSTORE_BANK_ITEM = 0xBADD, + CMSG_AUTOSTORE_BANK_ITEM = 0x00D5, CMSG_AUTOSTORE_GROUND_ITEM = 0xBADD, CMSG_AUTOSTORE_LOOT_ITEM = 0x0843, CMSG_BANKER_ACTIVATE = 0x0931, @@ -115,7 +115,7 @@ enum OpcodeClient : uint32 CMSG_BATTLE_PET_DELETE_PET = 0xBADD, CMSG_BATTLE_PET_DELETE_PET_CHEAT = 0xBADD, CMSG_BATTLE_PET_MODIFY_NAME = 0x1131, - CMSG_BATTLE_PET_NAME_QUERY = 0xBADD, + CMSG_BATTLE_PET_NAME_QUERY = 0x1184, CMSG_BATTLE_PET_REQUEST_JOURNAL = 0x1773, CMSG_BATTLE_PET_REQUEST_JOURNAL_LOCK = 0x1B24, CMSG_BATTLE_PET_REQUEST_UPDATE = 0xBADD, @@ -279,7 +279,7 @@ enum OpcodeClient : uint32 CMSG_GET_GARRISON_INFO = 0x0352, CMSG_GET_ITEM_PURCHASE_DATA = 0x0CE4, CMSG_GET_MAIL_LIST = 0x0979, - CMSG_GET_MIRROR_IMAGE_DATA = 0xBADD, + CMSG_GET_MIRROR_IMAGE_DATA = 0x1952, CMSG_GET_SHIPMENT_INFO = 0xBADD, CMSG_GET_TROPHY_LIST = 0xBADD, CMSG_GET_UNDELETE_COOLDOWN_STATUS = 0x196A, @@ -288,7 +288,7 @@ enum OpcodeClient : uint32 CMSG_GM_LAG_REPORT = 0xBADD, CMSG_GM_NUKE = 0xBADD, CMSG_GM_SET_SECURITY_GROUP = 0xBADD, - CMSG_GM_SURVEY_SUBMIT = 0xBADD, + CMSG_GM_SURVEY_SUBMIT = 0x1BAB, CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY = 0xBADD, CMSG_GM_TICKET_CREATE = 0x19A4, CMSG_GM_TICKET_DELETE_TICKET = 0x1B39, @@ -397,7 +397,7 @@ enum OpcodeClient : uint32 CMSG_LF_GUILD_SET_GUILD_POST = 0xBADD, CMSG_LIST_INVENTORY = 0x06C4, CMSG_LOAD_SCREEN = 0x13E4, - CMSG_LOGOUT_CANCEL = 0xBADD, + CMSG_LOGOUT_CANCEL = 0x0DC1, CMSG_LOGOUT_INSTANT = 0xBADD, CMSG_LOGOUT_REQUEST = 0x0824, CMSG_LOG_DISCONNECT = 0x1432, @@ -452,7 +452,7 @@ enum OpcodeClient : uint32 CMSG_MOVE_ENABLE_SWIM_TO_FLY_TRANS_ACK = 0x038B, CMSG_MOVE_FALL_LAND = 0x0DEA, CMSG_MOVE_FALL_RESET = 0x0F89, - CMSG_MOVE_FEATHER_FALL_ACK = 0x0F89, + CMSG_MOVE_FEATHER_FALL_ACK = 0x02B1, CMSG_MOVE_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK = 0xBADD, CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK = 0x09CB, CMSG_MOVE_FORCE_PITCH_RATE_CHANGE_ACK = 0xBADD, @@ -548,7 +548,7 @@ enum OpcodeClient : uint32 CMSG_PET_CAST_SPELL = 0xBADD, CMSG_PET_LEARN_TALENT = 0xBADD, CMSG_PET_NAME_CACHE = 0xBADD, - CMSG_PET_NAME_QUERY = 0xBADD, + CMSG_PET_NAME_QUERY = 0x0CCB, CMSG_PET_RENAME = 0x1333, CMSG_PET_SET_ACTION = 0xBADD, CMSG_PET_SET_SPECIALIZATION = 0xBADD, @@ -577,7 +577,7 @@ enum OpcodeClient : uint32 CMSG_QUESTGIVER_HELLO = 0x0B2A, CMSG_QUESTGIVER_QUERY_QUEST = 0x131A, CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0xBADD, - CMSG_QUESTGIVER_REQUEST_REWARD = 0xBADD, + CMSG_QUESTGIVER_REQUEST_REWARD = 0x1509, CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x0A39, CMSG_QUESTGIVER_STATUS_QUERY = 0x0A7B, CMSG_QUESTLOG_REMOVE_QUEST = 0x04C3, @@ -595,12 +595,12 @@ enum OpcodeClient : uint32 CMSG_REALM_NAME_QUERY = 0x17BC, CMSG_RECLAIM_CORPSE = 0x093B, CMSG_RECRUIT_A_FRIEND = 0xBADD, - CMSG_REGISTER_ADDON_PREFIXES = 0xBADD, + CMSG_REGISTER_ADDON_PREFIXES = 0x063B, CMSG_REORDER_CHARACTERS = 0x1729, CMSG_REPAIR_ITEM = 0x05E2, CMSG_REPLACE_ACCOUNT_DATA = 0xBADD, CMSG_REPLACE_TROPHY = 0xBADD, - CMSG_REPOP_REQUEST = 0xBADD, + CMSG_REPOP_REQUEST = 0x0B3B, CMSG_REPORT_FILTERED = 0xBADD, CMSG_REPORT_IGNORED = 0xBADD, CMSG_REPORT_PVP_AFK = 0xBADD, @@ -614,8 +614,8 @@ enum OpcodeClient : uint32 CMSG_REQUEST_GUILD_REWARDS_LIST = 0xBADD, CMSG_REQUEST_HONOR_STATS = 0xBADD, CMSG_REQUEST_LFG_LIST_BLACKLIST = 0xBADD, - CMSG_REQUEST_PARTY_JOIN_UPDATES = 0xBADD, - CMSG_REQUEST_PARTY_MEMBER_STATS = 0xBADD, + CMSG_REQUEST_PARTY_JOIN_UPDATES = 0x1339, + CMSG_REQUEST_PARTY_MEMBER_STATS = 0x1972, CMSG_REQUEST_PET_INFO = 0xBADD, CMSG_REQUEST_PVP_OPTIONS_ENABLED = 0xBADD, CMSG_REQUEST_PVP_REWARDS = 0xBADD, @@ -743,6 +743,7 @@ enum OpcodeClient : uint32 CMSG_TROPHY_MONUMENT_LOAD_SELECTED_TROPHY_ID = 0xBADD, CMSG_TURN_IN_PETITION = 0xBADD, CMSG_TUTORIAL_FLAG = 0x1132, + CMSG_TWITTER_GET_STATUS = 0x1128, CMSG_UI_TIME_REQUEST = 0x1B7B, CMSG_UNACCEPT_TRADE = 0xBADD, CMSG_UNDELETE_CHARACTER = 0xBADD, @@ -767,7 +768,7 @@ enum OpcodeClient : uint32 CMSG_VOICE_DEL_IGNORE = 0xBADD, CMSG_VOICE_SESSION_ENABLE = 0x153A, CMSG_VOID_STORAGE_QUERY = 0x17C3, - CMSG_VOID_STORAGE_TRANSFER = 0xBADD, + CMSG_VOID_STORAGE_TRANSFER = 0x0674, CMSG_VOID_STORAGE_UNLOCK = 0xBADD, CMSG_VOID_SWAP_ITEM = 0xBADD, CMSG_WARDEN_DATA = 0x11E3, @@ -892,8 +893,8 @@ enum OpcodeServer : uint32 SMSG_BATTLEGROUND_INIT = 0xBADD, SMSG_BATTLEGROUND_PLAYER_JOINED = 0xBADD, SMSG_BATTLEGROUND_PLAYER_LEFT = 0xBADD, - SMSG_BATTLEGROUND_PLAYER_POSITIONS = 0xBADD, - SMSG_BATTLEGROUND_POINTS = 0xBADD, + SMSG_BATTLEGROUND_PLAYER_POSITIONS = 0x1962, + SMSG_BATTLEGROUND_POINTS = 0x15AB, SMSG_BATTLENET_CHALLENGE_ABORT = 0xBADD, SMSG_BATTLENET_CHALLENGE_START = 0xBADD, SMSG_BATTLE_PAY_ACK_FAILED = 0xBADD, @@ -1306,7 +1307,7 @@ enum OpcodeServer : uint32 SMSG_LFG_PLAYER_INFO = 0x03FA, SMSG_LFG_PLAYER_REWARD = 0xBADD, SMSG_LFG_PROPOSAL_UPDATE = 0xBADD, - SMSG_LFG_QUEUE_STATUS = 0xBADD, + SMSG_LFG_QUEUE_STATUS = 0x0292, SMSG_LFG_ROLE_CHECK_UPDATE = 0xBADD, SMSG_LFG_ROLE_CHOSEN = 0xBADD, SMSG_LFG_SEARCH_RESULTS = 0xBADD, @@ -1314,7 +1315,7 @@ enum OpcodeServer : uint32 SMSG_LFG_TELEPORT_DENIED = 0xBADD, SMSG_LFG_UPDATE_LIST = 0xBADD, SMSG_LFG_UPDATE_SEARCH = 0xBADD, - SMSG_LFG_UPDATE_STATUS = 0xBADD, + SMSG_LFG_UPDATE_STATUS = 0x02B1, SMSG_LF_GUILD_APPLICANT_LIST_UPDATED = 0xBADD, SMSG_LF_GUILD_APPLICATIONS = 0xBADD, SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED = 0xBADD, @@ -1485,10 +1486,10 @@ enum OpcodeServer : uint32 SMSG_PARTY_COMMAND_RESULT = 0xBADD, SMSG_PARTY_INVITE = 0x1F9C, SMSG_PARTY_KILL_LOG = 0x0CA4, - SMSG_PARTY_MEMBER_STATE = 0xBADD, + SMSG_PARTY_MEMBER_STATE = 0x1564, SMSG_PARTY_MEMBER_STATS = 0xBADD, SMSG_PARTY_MEMBER_STATS_FULL = 0xBADD, - SMSG_PARTY_UPDATE = 0xBADD, + SMSG_PARTY_UPDATE = 0x0981, SMSG_PAUSE_MIRROR_TIMER = 0xBADD, SMSG_PENDING_RAID_LOCK = 0xBADD, SMSG_PERIODICAURALOG = 0x184B, @@ -1612,7 +1613,7 @@ enum OpcodeServer : uint32 SMSG_REFER_A_FRIEND_EXPIRED = 0xBADD, SMSG_REFER_A_FRIEND_FAILURE = 0xBADD, SMSG_REFRESH_COMPONENT = 0xBADD, - SMSG_REFRESH_SPELL_HISTORY = 0xBADD, + SMSG_REFRESH_SPELL_HISTORY = 0x072B, SMSG_REMOVE_ITEM_PASSIVE = 0xBADD, SMSG_REMOVE_LOSS_OF_CONTROL = 0xBADD, SMSG_REPLACE_TROPHY_RESPONSE = 0xBADD, @@ -1686,7 +1687,7 @@ enum OpcodeServer : uint32 SMSG_SET_FACTION_STANDING = 0x1129, SMSG_SET_FACTION_VISIBLE = 0x0A72, SMSG_SET_FLAT_SPELL_MODIFIER = 0x120B, - SMSG_SET_FORCED_REACTIONS = 0xBADD, + SMSG_SET_FORCED_REACTIONS = 0x0EC2, SMSG_SET_ITEM_PURCHASE_DATA = 0xBADD, SMSG_SET_LFG_TIME_WALKER = 0xBADD, SMSG_SET_LOOT_METHOD_FAILED = 0xBADD, @@ -1815,10 +1816,10 @@ enum OpcodeServer : uint32 SMSG_VOICE_SESSION_ROSTER_UPDATE = 0xBADD, SMSG_VOICE_SET_TALKER_MUTED = 0xBADD, SMSG_VOID_ITEM_SWAP_RESPONSE = 0xBADD, - SMSG_VOID_STORAGE_CONTENTS = 0xBADD, + SMSG_VOID_STORAGE_CONTENTS = 0x1122, SMSG_VOID_STORAGE_FAILED = 0xBADD, - SMSG_VOID_STORAGE_TRANSFER_CHANGES = 0xBADD, - SMSG_VOID_TRANSFER_RESULT = 0xBADD, + SMSG_VOID_STORAGE_TRANSFER_CHANGES = 0x1BAB, + SMSG_VOID_TRANSFER_RESULT = 0x192C, SMSG_WAIT_QUEUE_FINISH = 0xBADD, SMSG_WAIT_QUEUE_UPDATE = 0xBADD, SMSG_WARDEN_DATA = 0x110A, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 48c79fb9df2..61c27ff57d8 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -90,6 +90,13 @@ namespace WorldPackets enum class ConnectToSerial : uint32; } + namespace Bank + { + class AutoBankItem; + class AutoStoreBankItem; + class BuyBankSlot; + } + namespace BlackMarket { class BlackMarketOpen; @@ -289,6 +296,7 @@ namespace WorldPackets class MoveTeleportAck; class MovementAck; class MovementSpeedAck; + class SetActiveMover; } namespace NPC @@ -913,7 +921,7 @@ class WorldSession void HandleMoveWorldportAckOpcode(); // for server-side calls void HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMovement& packet); - void HandleSetActiveMoverOpcode(WorldPacket& recvData); + void HandleSetActiveMoverOpcode(WorldPackets::Movement::SetActiveMover& packet); void HandleMoveNotActiveMover(WorldPacket& recvData); void HandleDismissControlledVehicle(WorldPacket& recvData); void HandleRequestVehicleExit(WorldPacket& recvData); @@ -1002,7 +1010,6 @@ class WorldSession void HandleTabardVendorActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet); - void HandleBuyBankSlotOpcode(WorldPacket& recvPacket); void HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet); void HandleTrainerBuySpellOpcode(WorldPacket& recvPacket); void HandlePetitionShowList(WorldPackets::Petition::PetitionShowList& packet); @@ -1046,6 +1053,11 @@ class WorldSession void HandleAuctionPlaceBid(WorldPacket& recvData); void HandleAuctionListPendingSales(WorldPacket& recvData); + // Bank + void HandleAutoBankItemOpcode(WorldPackets::Bank::AutoBankItem& packet); + void HandleAutoStoreBankItemOpcode(WorldPackets::Bank::AutoStoreBankItem& packet); + void HandleBuyBankSlotOpcode(WorldPackets::Bank::BuyBankSlot& packet); + // Black Market void HandleBlackMarketOpen(WorldPackets::BlackMarket::BlackMarketOpen& packet); @@ -1075,8 +1087,6 @@ class WorldSession void HandleAutoEquipItemSlotOpcode(WorldPacket& recvPacket); void HandleSwapItem(WorldPackets::Item::SwapItem& swapItem); void HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet); - void HandleAutoBankItemOpcode(WorldPacket& recvPacket); - void HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket); void HandleWrapItemOpcode(WorldPacket& recvPacket); void HandleAttackSwingOpcode(WorldPackets::Combat::AttackSwing& packet); diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 112893fbc75..7e60ac9b5da 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -535,7 +535,12 @@ enum AuraType SPELL_AURA_476 = 476, SPELL_AURA_477 = 477, SPELL_AURA_478 = 478, - TOTAL_AURAS = 479 // 6.0.3 + SPELL_AURA_479 = 479, + SPELL_AURA_480 = 480, + SPELL_AURA_481 = 481, + SPELL_AURA_482 = 482, + SPELL_AURA_483 = 483, + TOTAL_AURAS = 484 }; enum AuraObjectType diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index dd90e10f7bb..e35b1a0a6b1 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -539,6 +539,11 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //476 &AuraEffect::HandleNULL, //477 &AuraEffect::HandleNULL, //478 + &AuraEffect::HandleNULL, //479 + &AuraEffect::HandleNULL, //480 + &AuraEffect::HandleNULL, //481 + &AuraEffect::HandleNULL, //482 + &AuraEffect::HandleNULL, //483 }; AuraEffect::AuraEffect(Aura* base, uint32 effIndex, int32 *baseAmount, Unit* caster) : diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index a5afe74728f..d464e305462 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -317,6 +317,12 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //242 SPELL_EFFECT_242 &Spell::EffectNULL, //243 SPELL_EFFECT_243 &Spell::EffectNULL, //244 SPELL_EFFECT_244 + &Spell::EffectNULL, //244 SPELL_EFFECT_245 + &Spell::EffectNULL, //244 SPELL_EFFECT_246 + &Spell::EffectNULL, //244 SPELL_EFFECT_247 + &Spell::EffectNULL, //244 SPELL_EFFECT_248 + &Spell::EffectNULL, //244 SPELL_EFFECT_249 + &Spell::EffectNULL, //244 SPELL_EFFECT_250 }; void Spell::EffectNULL(SpellEffIndex /*effIndex*/) diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 13026b56fc2..79d3cea0868 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading + ${CMAKE_SOURCE_DIR}/src/server/shared/Updater ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_SOURCE_DIR}/src/server/collision diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt index d5e445230bd..8c3f3216e91 100644 --- a/src/server/scripts/Kalimdor/CMakeLists.txt +++ b/src/server/scripts/Kalimdor/CMakeLists.txt @@ -92,7 +92,6 @@ set(scripts_STAT_SRCS Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp - Kalimdor/zone_mulgore.cpp Kalimdor/zone_bloodmyst_isle.cpp Kalimdor/zone_thunder_bluff.cpp Kalimdor/zone_azshara.cpp diff --git a/src/server/scripts/Kalimdor/zone_mulgore.cpp b/src/server/scripts/Kalimdor/zone_mulgore.cpp deleted file mode 100644 index b6db431d0b2..00000000000 --- a/src/server/scripts/Kalimdor/zone_mulgore.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* ScriptData -SDName: Mulgore -SD%Complete: 100 -SDComment: Support for quest: 11129, 861 -SDCategory: Mulgore -EndScriptData */ - -/* ContentData -npc_kyle_frenzied -EndContentData */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "Player.h" -#include "SpellInfo.h" - -/*##### -# npc_kyle_frenzied -######*/ - -enum KyleFrenzied -{ - EMOTE_SEE_LUNCH = 0, - EMOTE_EAT_LUNCH = 1, - EMOTE_DANCE = 2, - - SPELL_LUNCH = 42222, - NPC_KYLE_FRENZIED = 23616, - NPC_KYLE_FRIENDLY = 23622, - POINT_ID = 1 -}; - -class npc_kyle_frenzied : public CreatureScript -{ -public: - npc_kyle_frenzied() : CreatureScript("npc_kyle_frenzied") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_kyle_frenziedAI (creature); - } - - struct npc_kyle_frenziedAI : public ScriptedAI - { - npc_kyle_frenziedAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } - - void Initialize() - { - EventActive = false; - IsMovingToLunch = false; - PlayerGUID.Clear(); - EventTimer = 5000; - EventPhase = 0; - } - - bool EventActive; - bool IsMovingToLunch; - ObjectGuid PlayerGUID; - uint32 EventTimer; - uint8 EventPhase; - - void Reset() override - { - Initialize(); - - if (me->GetEntry() == NPC_KYLE_FRIENDLY) - me->UpdateEntry(NPC_KYLE_FRENZIED); - } - - void SpellHit(Unit* Caster, SpellInfo const* Spell) - { - if (!me->GetVictim() && !EventActive && Spell->Id == SPELL_LUNCH) - { - if (Caster->GetTypeId() == TYPEID_PLAYER) - PlayerGUID = Caster->GetGUID(); - - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - { - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - } - - EventActive = true; - Talk(EMOTE_SEE_LUNCH); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CREATURE_SPECIAL); - } - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE || !EventActive) - return; - - if (pointId == POINT_ID) - IsMovingToLunch = false; - } - - void UpdateAI(uint32 diff) override - { - if (EventActive) - { - if (IsMovingToLunch) - return; - - if (EventTimer <= diff) - { - EventTimer = 5000; - ++EventPhase; - - switch (EventPhase) - { - case 1: - if (Unit* unit = ObjectAccessor::GetUnit(*me, PlayerGUID)) - { - if (GameObject* go = unit->GetGameObject(SPELL_LUNCH)) - { - IsMovingToLunch = true; - me->GetMotionMaster()->MovePoint(POINT_ID, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()); - } - } - break; - case 2: - Talk(EMOTE_EAT_LUNCH); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING); - break; - case 3: - if (Player* unit = ObjectAccessor::GetPlayer(*me, PlayerGUID)) - unit->TalkedToCreature(me->GetEntry(), me->GetGUID()); - - me->UpdateEntry(NPC_KYLE_FRIENDLY); - break; - case 4: - EventTimer = 30000; - Talk(EMOTE_DANCE); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCESPECIAL); - break; - case 5: - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - Reset(); - me->GetMotionMaster()->Clear(); - break; - } - } - else - EventTimer -= diff; - } - } - }; - -}; - -void AddSC_mulgore() -{ - new npc_kyle_frenzied(); -} diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp index 232261df951..1c9d5cf2c62 100644 --- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp +++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp @@ -654,6 +654,7 @@ public: if (quest->GetQuestId() == QUEST_ESCAPE) { creature->setFaction(FACTION_RATCHET); + creature->AI()->Talk(SAY_START); if (npc_escortAI* pEscortAI = CAST_AI(npc_wizzlecrank_shredder::npc_wizzlecrank_shredderAI, creature->AI())) pEscortAI->Start(true, false, player->GetGUID()); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index 861956d435e..b751c1db10d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -255,12 +255,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript if (GetBossState(BOSS_VALKIRIES) == SPECIAL) state = DONE; break; - case DONE: - if (instance->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE) - EventStage = 4020; - else - EventStage = 4030; - break; default: break; } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp index 16526b694e9..974bd4672f1 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -133,7 +133,7 @@ class npc_announcer_toc10 : public CreatureScript char const* _message = "We are ready!"; - if (player->IsInCombat() || instance->IsEncounterInProgress() || instance->GetData(TYPE_EVENT)) + if (player->IsInCombat() || instance->IsEncounterInProgress()) return true; uint8 i = 0; @@ -199,17 +199,11 @@ class npc_announcer_toc10 : public CreatureScript } else if (instance->GetBossState(BOSS_LICH_KING) != DONE) { - if (GameObject* floor = ObjectAccessor::GetGameObject(*player, instance->GetGuidData(GO_ARGENT_COLISEUM_FLOOR))) - floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); - - creature->CastSpell(creature, SPELL_CORPSE_TELEPORT, false); - creature->CastSpell(creature, SPELL_DESTROY_FLOOR_KNOCKUP, false); - - if (!ObjectAccessor::GetCreature(*creature, instance->GetGuidData(NPC_ANUBARAK))) - creature->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); - - if (creature->IsVisible()) - creature->SetVisible(false); + if (creature->GetMap()->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE) + instance->SetData(TYPE_EVENT, 4020); + else + instance->SetData(TYPE_EVENT, 4030); + instance->SetBossState(BOSS_LICH_KING, NOT_STARTED); } creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); return true; diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index f6b9f9fb6be..b58d9419e95 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -29,7 +29,6 @@ npc_corastrasza npc_sinkhole_kill_credit npc_khunok_the_behemoth npc_nerubar_victim -npc_keristrasza npc_nesingwary_trapper npc_lurgglbr npc_nexus_drake_hatchling @@ -223,48 +222,6 @@ public: }; /*###### -## npc_keristrasza -######*/ - -enum Keristrasza -{ - SPELL_TELEPORT_TO_SARAGOSA = 46772 -}; - -#define GOSSIP_HELLO_KERI "I am prepared to face Saragosa!" - -class npc_keristrasza : public CreatureScript -{ -public: - npc_keristrasza() : CreatureScript("npc_keristrasza") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(11957) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_KERI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } - - bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_TELEPORT_TO_SARAGOSA, true); - } - - return true; - } -}; - -/*###### ## npc_corastrasza ######*/ @@ -2488,7 +2445,6 @@ void AddSC_borean_tundra() { new npc_sinkhole_kill_credit(); new npc_khunok_the_behemoth(); - new npc_keristrasza(); new npc_corastrasza(); new npc_iruk(); new npc_nerubar_victim(); diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 287e3591f5d..f3c8396832c 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2495,6 +2495,36 @@ public: } }; +class spell_q12414_hand_over_reins : public SpellScriptLoader +{ + public: + spell_q12414_hand_over_reins() : SpellScriptLoader("spell_q12414_hand_over_reins") { } + + class spell_q12414_hand_over_reins_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12414_hand_over_reins_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + GetHitUnit()->ExitVehicle(); + + if (caster) + caster->DespawnOrUnsummon(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q12414_hand_over_reins_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q12414_hand_over_reins_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -2555,4 +2585,5 @@ void AddSC_quest_spell_scripts() new spell_q10929_fumping(); new spell_q28813_get_our_boys_back_dummy(); new spell_q28813_set_health_random(); + new spell_q12414_hand_over_reins(); } diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index b6ac8b03099..657b3fde349 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -22,6 +22,7 @@ file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h) file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h) file(GLOB_RECURSE sources_Realm Realm/*.cpp Realm/*.h) file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h) +file(GLOB_RECURSE sources_Updater Updater/*.cpp Updater/*.h) file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h) file(GLOB sources_localdir *.cpp *.h) @@ -53,6 +54,7 @@ set(shared_STAT_SRCS ${sources_Packets} ${sources_Realm} ${sources_Threading} + ${sources_Updater} ${sources_Utilities} ${sources_localdir} ) @@ -63,6 +65,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/utf8cpp + ${CMAKE_SOURCE_DIR}/dep/process ${CMAKE_SOURCE_DIR}/src/server ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Configuration @@ -77,6 +80,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Realm ${CMAKE_CURRENT_SOURCE_DIR}/Threading ${CMAKE_CURRENT_SOURCE_DIR}/Utilities + ${CMAKE_CURRENT_SOURCE_DIR}/Updater ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} diff --git a/src/server/shared/Database/DatabaseLoader.cpp b/src/server/shared/Database/DatabaseLoader.cpp new file mode 100644 index 00000000000..25c400fdfa8 --- /dev/null +++ b/src/server/shared/Database/DatabaseLoader.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DatabaseLoader.h" +#include "DBUpdater.h" +#include "Config.h" + +#include <mysqld_error.h> + +DatabaseLoader::DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask) + : _logger(logger), _autoSetup(sConfigMgr->GetBoolDefault("Updates.AutoSetup", true)), + _updateFlags(sConfigMgr->GetIntDefault("Updates.EnableDatabases", defaultUpdateMask)) +{ +} + +template <class T> +DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name) +{ + bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags); + + _open.push(std::make_pair([this, name, updatesEnabledForThis, &pool]() -> bool + { + std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", ""); + if (dbString.empty()) + { + TC_LOG_ERROR(_logger.c_str(), "Database %s not specified in configuration file!", name.c_str()); + return false; + } + + uint8 const asyncThreads = uint8(sConfigMgr->GetIntDefault(name + "Database.WorkerThreads", 1)); + if (asyncThreads < 1 || asyncThreads > 32) + { + TC_LOG_ERROR(_logger.c_str(), "%s database: invalid number of worker threads specified. " + "Please pick a value between 1 and 32.", name.c_str()); + return false; + } + + uint8 const synchThreads = uint8(sConfigMgr->GetIntDefault(name + "Database.SynchThreads", 1)); + + pool.SetConnectionInfo(dbString, asyncThreads, synchThreads); + if (uint32 error = pool.Open()) + { + // Database does not exist + if ((error == ER_BAD_DB_ERROR) && updatesEnabledForThis && _autoSetup) + { + // Try to create the database and connect again if auto setup is enabled + if (DBUpdater<T>::Create(pool) && (!pool.Open())) + error = 0; + } + + // If the error wasn't handled quit + if (error) + { + TC_LOG_ERROR("sql.driver", "\nDatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " + "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", name.c_str()); + + return false; + } + } + return true; + }, + [&pool]() + { + pool.Close(); + })); + + // Populate and update only if updates are enabled for this pool + if (updatesEnabledForThis) + { + _populate.push([this, name, &pool]() -> bool + { + if (!DBUpdater<T>::Populate(pool)) + { + TC_LOG_ERROR(_logger.c_str(), "Could not populate the %s database, see log for details.", name.c_str()); + return false; + } + return true; + }); + + _update.push([this, name, &pool]() -> bool + { + if (!DBUpdater<T>::Update(pool)) + { + TC_LOG_ERROR(_logger.c_str(), "Could not update the %s database, see log for details.", name.c_str()); + return false; + } + return true; + }); + } + + _prepare.push([this, name, &pool]() -> bool + { + if (!pool.PrepareStatements()) + { + TC_LOG_ERROR(_logger.c_str(), "Could not prepare statements of the %s database, see log for details.", name.c_str()); + return false; + } + return true; + }); + + return *this; +} + +bool DatabaseLoader::Load() +{ + if (!OpenDatabases()) + return false; + + if (!PopulateDatabases()) + return false; + + if (!UpdateDatabases()) + return false; + + if (!PrepareStatements()) + return false; + + return true; +} + +bool DatabaseLoader::OpenDatabases() +{ + while (!_open.empty()) + { + std::pair<Predicate, std::function<void()>> const load = _open.top(); + if (load.first()) + _close.push(load.second); + else + { + // Close all loaded databases + while (!_close.empty()) + { + _close.top()(); + _close.pop(); + } + return false; + } + + _open.pop(); + } + return true; +} + +// Processes the elements of the given stack until a predicate returned false. +bool DatabaseLoader::Process(std::stack<Predicate>& stack) +{ + while (!stack.empty()) + { + if (!stack.top()()) + return false; + + stack.pop(); + } + return true; +} + +bool DatabaseLoader::PopulateDatabases() +{ + return Process(_populate); +} + +bool DatabaseLoader::UpdateDatabases() +{ + return Process(_update); +} + +bool DatabaseLoader::PrepareStatements() +{ + return Process(_prepare); +} + +template +DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>& pool, std::string const& name); +template +DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>& pool, std::string const& name); +template +DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>& pool, std::string const& name); +template +DatabaseLoader& DatabaseLoader::AddDatabase<HotfixDatabaseConnection>(DatabaseWorkerPool<HotfixDatabaseConnection>& pool, std::string const& name); diff --git a/src/server/shared/Database/DatabaseLoader.h b/src/server/shared/Database/DatabaseLoader.h new file mode 100644 index 00000000000..3bbf7e75771 --- /dev/null +++ b/src/server/shared/Database/DatabaseLoader.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DatabaseLoader_h__ +#define DatabaseLoader_h__ + +#include "DatabaseWorkerPool.h" +#include "DatabaseEnv.h" + +#include <stack> +#include <functional> + +// A helper class to initiate all database worker pools, +// handles updating, delays preparing of statements and cleans up on failure. +class DatabaseLoader +{ +public: + DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask); + + // Register a database to the loader (lazy implemented) + template <class T> + DatabaseLoader& AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name); + + // Load all databases + bool Load(); + + enum DatabaseTypeFlags + { + DATABASE_NONE = 0, + + DATABASE_LOGIN = 1, + DATABASE_CHARACTER = 2, + DATABASE_WORLD = 4, + DATABASE_HOTFIX = 8, + + DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD | DATABASE_HOTFIX + }; + +private: + bool OpenDatabases(); + bool PopulateDatabases(); + bool UpdateDatabases(); + bool PrepareStatements(); + + using Predicate = std::function<bool()>; + + static bool Process(std::stack<Predicate>& stack); + + std::string const _logger; + bool const _autoSetup; + uint32 const _updateFlags; + + std::stack<std::pair<Predicate, std::function<void()>>> _open; + std::stack<std::function<void()>> _close; + std::stack<Predicate> _populate, _update, _prepare; +}; + +#endif // DatabaseLoader_h__ diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index f1c6a7acbf5..6210986ff8b 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -30,6 +30,7 @@ #include "AdhocStatement.h" #include <mysqld_error.h> +#include <memory> #define MIN_MYSQL_SERVER_VERSION 50100u #define MIN_MYSQL_CLIENT_VERSION 50100u @@ -57,9 +58,9 @@ class DatabaseWorkerPool public: /* Activity state */ - DatabaseWorkerPool() : _connectionInfo(NULL) + DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()), + _async_threads(0), _synch_threads(0) { - _queue = new ProducerConsumerQueue<SQLOperation*>(); memset(_connectionCount, 0, sizeof(_connectionCount)); _connections.resize(IDX_SIZE); @@ -70,31 +71,37 @@ class DatabaseWorkerPool ~DatabaseWorkerPool() { _queue->Cancel(); + } - delete _queue; + void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads) + { + _connectionInfo.reset(new MySQLConnectionInfo(infoString)); - delete _connectionInfo; + _async_threads = asyncThreads; + _synch_threads = synchThreads; } - bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads) + uint32 Open() { - _connectionInfo = new MySQLConnectionInfo(infoString); + WPFatal(_connectionInfo.get(), "Connection info was not set!"); TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", - GetDatabaseName(), async_threads, synch_threads); + GetDatabaseName(), _async_threads, _synch_threads); - bool res = OpenConnections(IDX_ASYNC, async_threads); + uint32 error = OpenConnections(IDX_ASYNC, _async_threads); - if (!res) - return res; + if (error) + return error; - res = OpenConnections(IDX_SYNCH, synch_threads); + error = OpenConnections(IDX_SYNCH, _synch_threads); - if (res) + if (!error) + { TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC])); + } - return res; + return error; } void Close() @@ -120,6 +127,32 @@ class DatabaseWorkerPool TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); } + //! Prepares all prepared statements + bool PrepareStatements() + { + for (uint8 i = 0; i < IDX_SIZE; ++i) + for (uint32 c = 0; c < _connectionCount[i]; ++c) + { + T* t = _connections[i][c]; + t->LockIfReady(); + if (!t->PrepareStatements()) + { + t->Unlock(); + Close(); + return false; + } + else + t->Unlock(); + } + + return true; + } + + inline MySQLConnectionInfo const* GetConnectionInfo() const + { + return _connectionInfo.get(); + } + /** Delayed one-way statement methods. */ @@ -461,7 +494,7 @@ class DatabaseWorkerPool } private: - bool OpenConnections(InternalIndex type, uint8 numConnections) + uint32 OpenConnections(InternalIndex type, uint8 numConnections) { _connections[type].resize(numConnections); for (uint8 i = 0; i < numConnections; ++i) @@ -469,7 +502,7 @@ class DatabaseWorkerPool T* t; if (type == IDX_ASYNC) - t = new T(_queue, *_connectionInfo); + t = new T(_queue.get(), *_connectionInfo); else if (type == IDX_SYNCH) t = new T(*_connectionInfo); else @@ -478,35 +511,32 @@ class DatabaseWorkerPool _connections[type][i] = t; ++_connectionCount[type]; - bool res = t->Open(); + uint32 error = t->Open(); - if (res) + if (!error) { if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION) { TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); - res = false; + error = 1; } } // Failed to open a connection or invalid version, abort and cleanup - if (!res) + if (error) { - TC_LOG_ERROR("sql.driver", "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " - "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", GetDatabaseName()); - while (_connectionCount[type] != 0) { T* t = _connections[type][i--]; delete t; --_connectionCount[type]; } - - return false; + return error; } } - return true; + // Everything is fine + return 0; } unsigned long EscapeString(char *to, const char *from, unsigned long length) @@ -546,10 +576,13 @@ class DatabaseWorkerPool return _connectionInfo->database.c_str(); } - ProducerConsumerQueue<SQLOperation*>* _queue; //! Queue shared by async worker threads. - std::vector< std::vector<T*> > _connections; - uint32 _connectionCount[2]; //! Counter of MySQL connections; - MySQLConnectionInfo* _connectionInfo; + //! Queue shared by async worker threads. + std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue; + std::vector<std::vector<T*>> _connections; + //! Counter of MySQL connections; + uint32 _connectionCount[IDX_SIZE]; + std::unique_ptr<MySQLConnectionInfo> _connectionInfo; + uint8 _async_threads, _synch_threads; }; #endif diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 1a9f973d47b..1fa3f01a5e1 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -72,7 +72,7 @@ void MySQLConnection::Close() delete this; } -bool MySQLConnection::Open() +uint32 MySQLConnection::Open() { MYSQL *mysqlInit; mysqlInit = mysql_init(NULL); @@ -137,13 +137,13 @@ bool MySQLConnection::Open() // set connection properties to UTF8 to properly handle locales for different // server configs - core sends data in UTF8, so MySQL must expect UTF8 too mysql_set_character_set(m_Mysql, "utf8"); - return PrepareStatements(); + return 0; } else { - TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s\n", m_connectionInfo.host.c_str(), mysql_error(mysqlInit)); + TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit)); mysql_close(mysqlInit); - return false; + return mysql_errno(mysqlInit); } } diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h index d486f5b4679..78d8d2fb5dd 100644 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -72,9 +72,11 @@ class MySQLConnection MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections. virtual ~MySQLConnection(); - virtual bool Open(); + virtual uint32 Open(); void Close(); + bool PrepareStatements(); + public: bool Execute(const char* sql); bool Execute(PreparedStatement* stmt); @@ -111,7 +113,6 @@ class MySQLConnection MySQLPreparedStatement* GetPreparedStatement(uint32 index); void PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags); - bool PrepareStatements(); virtual void DoPrepareStatements() = 0; protected: diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp new file mode 100644 index 00000000000..156c2a8fdd4 --- /dev/null +++ b/src/server/shared/Updater/DBUpdater.cpp @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DBUpdater.h" +#include "Log.h" +#include "revision.h" +#include "UpdateFetcher.h" +#include "DatabaseLoader.h" +#include "Config.h" + +#include <fstream> +#include <iostream> +#include <unordered_map> +#include <boost/process.hpp> +#include <boost/process/mitigate.hpp> +#include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/system/system_error.hpp> + +using namespace boost::process; +using namespace boost::process::initializers; +using namespace boost::iostreams; + +template<class T> +std::string DBUpdater<T>::GetSourceDirectory() +{ + std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", ""); + if (!entry.empty()) + return entry; + else + return _SOURCE_DIRECTORY; +} + +template<class T> +std::string DBUpdater<T>::GetMySqlCli() +{ + std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", ""); + if (!entry.empty()) + return entry; + else + return _MYSQL_EXECUTABLE; +} + +// Auth Database +template<> +std::string DBUpdater<LoginDatabaseConnection>::GetConfigEntry() +{ + return "Updates.Auth"; +} + +template<> +std::string DBUpdater<LoginDatabaseConnection>::GetTableName() +{ + return "Auth"; +} + +template<> +std::string DBUpdater<LoginDatabaseConnection>::GetBaseFile() +{ + return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/sql/base/auth_database.sql"; +} + +template<> +bool DBUpdater<LoginDatabaseConnection>::IsEnabled(uint32 const updateMask) +{ + // This way silences warnings under msvc + return (updateMask & DatabaseLoader::DATABASE_LOGIN) ? true : false; +} + +// World Database +template<> +std::string DBUpdater<WorldDatabaseConnection>::GetConfigEntry() +{ + return "Updates.World"; +} + +template<> +std::string DBUpdater<WorldDatabaseConnection>::GetTableName() +{ + return "World"; +} + +template<> +std::string DBUpdater<WorldDatabaseConnection>::GetBaseFile() +{ + return _FULL_DATABASE; +} + +template<> +bool DBUpdater<WorldDatabaseConnection>::IsEnabled(uint32 const updateMask) +{ + // This way silences warnings under msvc + return (updateMask & DatabaseLoader::DATABASE_WORLD) ? true : false; +} + +template<> +BaseLocation DBUpdater<WorldDatabaseConnection>::GetBaseLocationType() +{ + return LOCATION_DOWNLOAD; +} + +// Character Database +template<> +std::string DBUpdater<CharacterDatabaseConnection>::GetConfigEntry() +{ + return "Updates.Character"; +} + +template<> +std::string DBUpdater<CharacterDatabaseConnection>::GetTableName() +{ + return "Character"; +} + +template<> +std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFile() +{ + return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/sql/base/characters_database.sql"; +} + +template<> +bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask) +{ + // This way silences warnings under msvc + return (updateMask & DatabaseLoader::DATABASE_CHARACTER) ? true : false; +} + +// Hotfix Database +template<> +std::string DBUpdater<HotfixDatabaseConnection>::GetConfigEntry() +{ + return "Updates.Hotfix"; +} + +template<> +std::string DBUpdater<HotfixDatabaseConnection>::GetTableName() +{ + return "Hotfixes"; +} + +template<> +std::string DBUpdater<HotfixDatabaseConnection>::GetBaseFile() +{ + return _HOTFIXES_DATABASE; +} + +template<> +bool DBUpdater<HotfixDatabaseConnection>::IsEnabled(uint32 const updateMask) +{ + // This way silences warnings under msvc + return (updateMask & DatabaseLoader::DATABASE_HOTFIX) ? true : false; +} + +template<> +BaseLocation DBUpdater<HotfixDatabaseConnection>::GetBaseLocationType() +{ + return LOCATION_DOWNLOAD; +} + +// All +template<class T> +BaseLocation DBUpdater<T>::GetBaseLocationType() +{ + return LOCATION_REPOSITORY; +} + +template<class T> +bool DBUpdater<T>::CheckExecutable() +{ + DBUpdater<T>::Path const exe(DBUpdater<T>::GetMySqlCli()); + if (!exists(exe)) + { + // Check for mysql in path + std::vector<std::string> args = {"--version"}; + uint32 ret; + try + { + child c = execute(run_exe("mysql"), set_args(args), throw_on_error(), close_stdout()); + ret = wait_for_exit(c); + } + catch (boost::system::system_error&) + { + ret = EXIT_FAILURE; + } + + if (ret == EXIT_FAILURE) + { + TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\', correct the path in the *.conf (\"Updates.MySqlCLIPath\").", + absolute(exe).generic_string().c_str()); + + return false; + } + } + return true; +} + +template<class T> +bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool) +{ + TC_LOG_INFO("sql.updates", "Database \"%s\" does not exist, do you want to create it? [yes (default) / no]: ", + pool.GetConnectionInfo()->database.c_str()); + + std::string answer; + std::getline(std::cin, answer); + if (!answer.empty() && !(answer.substr(0, 1) == "y")) + return false; + + TC_LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str()); + + // Path of temp file + static Path const temp("create_table.sql"); + + // Create temporary query to use external mysql cli + std::ofstream file(temp.generic_string()); + if (!file.is_open()) + { + TC_LOG_FATAL("sql.updates", "Failed to create temporary query file \"%s\"!", temp.generic_string().c_str()); + return false; + } + + file << "CREATE DATABASE `" << pool.GetConnectionInfo()->database << "` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci\n\n"; + + file.close(); + + try + { + DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, + pool.GetConnectionInfo()->port_or_socket, "", temp); + } + catch (UpdateException&) + { + TC_LOG_FATAL("sql.updates", "Failed to create database %s! Has the user `CREATE` priviliges?", pool.GetConnectionInfo()->database.c_str()); + boost::filesystem::remove(temp); + return false; + } + + TC_LOG_INFO("sql.updates", "Done."); + boost::filesystem::remove(temp); + return true; +} + +template<class T> +bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool) +{ + if (!DBUpdater<T>::CheckExecutable()) + return false; + + TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str()); + + Path const sourceDirectory(GetSourceDirectory()); + + if (!is_directory(sourceDirectory)) + { + TC_LOG_ERROR("sql.updates", "DBUpdater: Given source directory %s does not exist, skipped!", sourceDirectory.generic_string().c_str()); + return false; + } + + UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const& query) { DBUpdater<T>::Apply(pool, query); }, + [&](Path const& file) { DBUpdater<T>::ApplyFile(pool, file); }, + [&](std::string const& query) -> QueryResult { return DBUpdater<T>::Retrieve(pool, query); }); + + uint32 const count = updateFetcher.Update( + sConfigMgr->GetBoolDefault("Updates.Redundancy", true), + sConfigMgr->GetBoolDefault("Updates.AllowRehash", true), + sConfigMgr->GetBoolDefault("Updates.ArchivedRedundancy", false), + sConfigMgr->GetBoolDefault("Updates.CleanDeadRef", true)); + + if (!count) + TC_LOG_INFO("sql.updates", ">> %s database is up-to-date!", DBUpdater<T>::GetTableName().c_str()); + else + TC_LOG_INFO("sql.updates", ">> Applied %d %s.", count, count == 1 ? "query" : "queries"); + + return true; +} + +template<class T> +bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool) +{ + { + QueryResult const result = Retrieve(pool, "SHOW TABLES"); + if (result && (result->GetRowCount() > 0)) + return true; + } + + if (!DBUpdater<T>::CheckExecutable()) + return false; + + TC_LOG_INFO("sql.updates", "Database %s is empty, auto populating it...", DBUpdater<T>::GetTableName().c_str()); + + std::string const p = DBUpdater<T>::GetBaseFile(); + if (p.empty()) + { + TC_LOG_INFO("sql.updates", ">> No base file provided, skipped!"); + return true; + } + + Path const base(p); + if (!exists(base)) + { + switch (DBUpdater<T>::GetBaseLocationType()) + { + case LOCATION_REPOSITORY: + { + TC_LOG_ERROR("sql.updates", ">> Base file \"%s\" is missing, try to clone the source again.", + base.generic_string().c_str(), base.filename().generic_string().c_str()); + + break; + } + case LOCATION_DOWNLOAD: + { + TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"http://www.trinitycore.org/f/files/category/1-database/\"" \ + " and place it in your server directory.", base.filename().generic_string().c_str()); + break; + } + } + return false; + } + + // Update database + TC_LOG_INFO("sql.updates", ">> Applying \'%s\'...", base.generic_string().c_str()); + ApplyFile(pool, base); + + TC_LOG_INFO("sql.updates", ">> Done!"); + return true; +} + +template<class T> +QueryResult DBUpdater<T>::Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query) +{ + return pool.PQuery(query.c_str()); +} + +template<class T> +void DBUpdater<T>::Apply(DatabaseWorkerPool<T>& pool, std::string const& query) +{ + pool.DirectExecute(query.c_str()); +} + +template<class T> +void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path) +{ + DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password, + pool.GetConnectionInfo()->port_or_socket, pool.GetConnectionInfo()->database, path); +} + +template<class T> +void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, + std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path) +{ + std::vector<std::string> args; + args.reserve(7); + + // CLI Client connection info + args.push_back("-h" + host); + args.push_back("-u" + user); + args.push_back("-p" + password); + args.push_back("-P" + port_or_socket); + + // Set the default charset to utf8 + args.push_back("--default-character-set=utf8"); + + // Set max allowed packet to 1 GB + args.push_back("--max-allowed-packet=1GB"); + + // Database + if (!database.empty()) + args.push_back(database); + + // ToDo: use the existing query in memory as virtual file if possible + file_descriptor_source source(path); + + uint32 ret; + try + { + child c = execute(run_exe(DBUpdater<T>::GetMySqlCli().empty() ? "mysql" : + boost::filesystem::absolute(DBUpdater<T>::GetMySqlCli()).generic_string()), + set_args(args), bind_stdin(source), throw_on_error()); + + ret = wait_for_exit(c); + } + catch (boost::system::system_error&) + { + ret = EXIT_FAILURE; + } + + source.close(); + + if (ret != EXIT_SUCCESS) + { + TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \ + " If you are an user pull the latest revision from the repository. If you are a developer fix your sql query.", + path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str()); + + throw UpdateException("update failed"); + } +} + +template class DBUpdater<LoginDatabaseConnection>; +template class DBUpdater<WorldDatabaseConnection>; +template class DBUpdater<CharacterDatabaseConnection>; +template class DBUpdater<HotfixDatabaseConnection>; diff --git a/src/server/shared/Updater/DBUpdater.h b/src/server/shared/Updater/DBUpdater.h new file mode 100644 index 00000000000..0caf8a438fb --- /dev/null +++ b/src/server/shared/Updater/DBUpdater.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DBUpdater_h__ +#define DBUpdater_h__ + +#include "DatabaseEnv.h" + +#include <string> +#include <boost/filesystem.hpp> + +class UpdateException : public std::exception +{ +public: + UpdateException(std::string const& msg) : _msg(msg) { } + ~UpdateException() throw() { } + + char const* what() const throw() override { return _msg.c_str(); } + +private: + std::string const _msg; +}; + +enum BaseLocation +{ + LOCATION_REPOSITORY, + LOCATION_DOWNLOAD +}; + +template <class T> +class DBUpdater +{ +public: + using Path = boost::filesystem::path; + + static std::string GetSourceDirectory(); + + static inline std::string GetConfigEntry(); + + static inline std::string GetTableName(); + + static std::string GetBaseFile(); + + static bool IsEnabled(uint32 const updateMask); + + static BaseLocation GetBaseLocationType(); + + static bool Create(DatabaseWorkerPool<T>& pool); + + static bool Update(DatabaseWorkerPool<T>& pool); + + static bool Populate(DatabaseWorkerPool<T>& pool); + +private: + static std::string GetMySqlCli(); + static bool CheckExecutable(); + + static QueryResult Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query); + static void Apply(DatabaseWorkerPool<T>& pool, std::string const& query); + static void ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path); + static void ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user, + std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path); +}; + +#endif // DBUpdater_h__ diff --git a/src/server/shared/Updater/UpdateFetcher.cpp b/src/server/shared/Updater/UpdateFetcher.cpp new file mode 100644 index 00000000000..8084c6ba37f --- /dev/null +++ b/src/server/shared/Updater/UpdateFetcher.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "UpdateFetcher.h" +#include "Log.h" +#include "Util.h" + +#include <fstream> +#include <chrono> +#include <vector> +#include <sstream> +#include <exception> +#include <unordered_map> +#include <openssl/sha.h> + +using namespace boost::filesystem; + +UpdateFetcher::UpdateFetcher(Path const& sourceDirectory, + std::function<void(std::string const&)> const& apply, + std::function<void(Path const& path)> const& applyFile, + std::function<QueryResult(std::string const&)> const& retrieve) : + _sourceDirectory(sourceDirectory), _apply(apply), _applyFile(applyFile), + _retrieve(retrieve) +{ +} + +UpdateFetcher::LocaleFileStorage UpdateFetcher::GetFileList() const +{ + LocaleFileStorage files; + DirectoryStorage directories = ReceiveIncludedDirectories(); + for (auto const& entry : directories) + FillFileListRecursively(entry.path, files, entry.state, 1); + + return files; +} + +void UpdateFetcher::FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const +{ + static uint32 const MAX_DEPTH = 10; + static directory_iterator const end; + + for (directory_iterator itr(path); itr != end; ++itr) + { + if (is_directory(itr->path())) + { + if (depth < MAX_DEPTH) + FillFileListRecursively(itr->path(), storage, state, depth + 1); + } + else if (itr->path().extension() == ".sql") + { + TC_LOG_TRACE("sql.updates", "Added locale file \"%s\".", itr->path().filename().generic_string().c_str()); + + LocaleFileEntry const entry = { itr->path(), state }; + + // Check for doubled filenames + // Since elements are only compared through 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()); + + throw UpdateException("Updating failed, see the log for details."); + } + + storage.insert(entry); + } + } +} + +UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() const +{ + DirectoryStorage directories; + + QueryResult const result = _retrieve("SELECT `path`, `state` FROM `updates_include`"); + if (!result) + return directories; + + do + { + Field* fields = result->Fetch(); + + std::string path = fields[0].GetString(); + if (path.substr(0, 1) == "$") + path = _sourceDirectory.generic_string() + path.substr(1); + + Path const p(path); + + if (!is_directory(p)) + { + TC_LOG_ERROR("sql.updates", "DBUpdater: Given update include directory \"%s\" isn't existing, skipped!", p.generic_string().c_str()); + continue; + } + + DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert(fields[1].GetString()) }; + directories.push_back(entry); + + TC_LOG_TRACE("sql.updates", "Added applied file \"%s\" from remote.", p.filename().generic_string().c_str()); + + } while (result->NextRow()); + + return directories; +} + +UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const +{ + AppliedFileStorage map; + + QueryResult result = _retrieve("SELECT `name`, `hash`, `state`, `timestamp` FROM `updates` ORDER BY `name` ASC"); + if (!result) + return map; + + do + { + Field* fields = result->Fetch(); + + AppliedFileEntry const entry = { fields[0].GetString(), fields[1].GetString(), + AppliedFileEntry::StateConvert(fields[2].GetString()), fields[3].GetUInt32() }; + + map.insert(std::make_pair(entry.name, entry)); + } + while (result->NextRow()); + + return map; +} + +UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const +{ + std::ifstream in(file.c_str()); + WPFatal(in.is_open(), "Could not read an update file."); + + auto const start_pos = in.tellg(); + in.ignore(std::numeric_limits<std::streamsize>::max()); + auto const char_count = in.gcount(); + in.seekg(start_pos); + + SQLUpdate const update(new std::string(char_count, char{})); + + in.read(&(*update)[0], update->size()); + in.close(); + return update; +} + +uint32 UpdateFetcher::Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, bool const cleanDeadReferences) const +{ + LocaleFileStorage const available = GetFileList(); + AppliedFileStorage applied = ReceiveAppliedFiles(); + + // Fill hash to name cache + HashToFileNameStorage hashToName; + for (auto entry : applied) + hashToName.insert(std::make_pair(entry.second.hash, entry.first)); + + uint32 importedUpdates = 0; + + for (auto const& availableQuery : available) + { + TC_LOG_DEBUG("sql.updates", "Checking update \"%s\"...", availableQuery.first.filename().generic_string().c_str()); + + 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 (!redundancyChecks) + { + TC_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks."); + applied.erase(iter); + 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 (!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."); + applied.erase(iter); + continue; + } + } + + // Read update from file + SQLUpdate const update = ReadSQLUpdate(availableQuery.first); + + // Calculate hash + std::string const hash = CalculateHash(update); + + UpdateMode mode = MODE_APPLY; + + // Update is not in our applied list + if (iter == applied.end()) + { + // 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. + LocaleFileStorage::const_iterator localeIter; + // Push localeIter forward + for (localeIter = available.begin(); (localeIter != available.end()) && + (localeIter->first.filename().string() != hashIter->second); ++localeIter); + + // 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\")", + 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 + else + { + TC_LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.", + hashIter->second.c_str(), availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str()); + + RenameEntry(hashIter->second, availableQuery.first.filename().string()); + applied.erase(hashIter->second); + continue; + } + } + // Apply the update if it was never seen before. + else + { + TC_LOG_INFO("sql.updates", ">> Applying update \"%s\" \'%s\'...", + 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. + else if (allowRehash && iter->second.hash.empty()) + { + mode = MODE_REHASH; + + TC_LOG_INFO("sql.updates", ">> Re-hashing update \"%s\" \'%s\'...", availableQuery.first.filename().string().c_str(), + hash.substr(0, 7).c_str()); + } + else + { + // If the hash of the files differs from the one stored in our database reapply the update (because it was changed). + if (iter->second.hash != hash) + { + TC_LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", availableQuery.first.filename().string().c_str(), + iter->second.hash.substr(0, 7).c_str(), hash.substr(0, 7).c_str()); + } + else + { + // 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\'...", + 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()); + + applied.erase(iter); + continue; + } + } + + uint32 speed = 0; + AppliedFileEntry const file = { availableQuery.first.filename().string(), hash, availableQuery.second, 0 }; + + switch (mode) + { + case MODE_APPLY: + speed = Apply(availableQuery.first); + /*no break*/ + case MODE_REHASH: + UpdateEntry(file, speed); + break; + } + + if (iter != applied.end()) + applied.erase(iter); + + if (mode == MODE_APPLY) + ++importedUpdates; + } + + for (auto const& entry : applied) + { + TC_LOG_WARN("sql.updates", ">> File \'%s\' was applied to the database but is missing in" \ + " your update directory now!%s", entry.first.c_str(), cleanDeadReferences ? " Deleting orphaned entry..." : ""); + } + + if (cleanDeadReferences) + CleanUp(applied); + + return importedUpdates; +} + +std::string UpdateFetcher::CalculateHash(SQLUpdate const& query) const +{ + // Calculate a Sha1 hash based on query content. + unsigned char digest[SHA_DIGEST_LENGTH]; + SHA1((unsigned char*)query->c_str(), query->length(), (unsigned char*)&digest); + + return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH); +} + +uint32 UpdateFetcher::Apply(Path const& path) const +{ + using Time = std::chrono::high_resolution_clock; + using ms = std::chrono::milliseconds; + + // Benchmark query speed + auto const begin = Time::now(); + + // Update database + _applyFile(path); + + // Return time the query took to apply + return std::chrono::duration_cast<ms>(Time::now() - begin).count(); +} + +void UpdateFetcher::UpdateEntry(AppliedFileEntry const& entry, uint32 const speed) const +{ + std::string const update = "REPLACE INTO `updates` (`name`, `hash`, `state`, `speed`) VALUES (\"" + + entry.name + "\", \"" + entry.hash + "\", \'" + entry.GetStateAsString() + "\', " + std::to_string(speed) + ")"; + + // Update database + _apply(update); +} + +void UpdateFetcher::RenameEntry(std::string const& from, std::string const& to) const +{ + // Delete target if it exists + { + std::string const update = "DELETE FROM `updates` WHERE `name`=\"" + to + "\""; + + // Update database + _apply(update); + } + + // Rename + { + std::string const update = "UPDATE `updates` SET `name`=\"" + to + "\" WHERE `name`=\"" + from + "\""; + + // Update database + _apply(update); + } +} + +void UpdateFetcher::CleanUp(AppliedFileStorage const& storage) const +{ + if (storage.empty()) + return; + + std::stringstream update; + size_t remaining = storage.size(); + + update << "DELETE FROM `updates` WHERE `name` IN("; + + for (auto const& entry : storage) + { + update << "\"" << entry.first << "\""; + if ((--remaining) > 0) + update << ", "; + } + + update << ")"; + + // Update database + _apply(update.str()); +} + +void UpdateFetcher::UpdateState(std::string const& name, State const state) const +{ + std::string const update = "UPDATE `updates` SET `state`=\'" + AppliedFileEntry::StateConvert(state) + "\' WHERE `name`=\"" + name + "\""; + + // Update database + _apply(update); +} diff --git a/src/server/shared/Updater/UpdateFetcher.h b/src/server/shared/Updater/UpdateFetcher.h new file mode 100644 index 00000000000..b348eecf4e1 --- /dev/null +++ b/src/server/shared/Updater/UpdateFetcher.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UpdateFetcher_h__ +#define UpdateFetcher_h__ + +#include <DBUpdater.h> + +#include <functional> +#include <string> +#include <memory> +#include <vector> +#include <boost/container/flat_set.hpp> + +class UpdateFetcher +{ + using Path = boost::filesystem::path; + +public: + UpdateFetcher(Path const& updateDirectory, + std::function<void(std::string const&)> const& apply, + std::function<void(Path const& path)> const& applyFile, + std::function<QueryResult(std::string const&)> const& retrieve); + + uint32 Update(bool const redundancyChecks, bool const allowRehash, + bool const archivedRedundancy, bool const cleanDeadReferences) const; + +private: + enum UpdateMode + { + MODE_APPLY, + MODE_REHASH + }; + + enum State + { + RELEASED, + ARCHIVED + }; + + struct AppliedFileEntry + { + std::string const name; + + std::string const hash; + + State const state; + + uint32 const timestamp; + + static inline State StateConvert(std::string const& state) + { + return (state == "RELEASED") ? RELEASED : ARCHIVED; + } + + static inline std::string StateConvert(State const state) + { + return (state == RELEASED) ? "RELEASED" : "ARCHIVED"; + } + + std::string GetStateAsString() const + { + return StateConvert(state); + } + }; + + struct DirectoryEntry + { + Path const path; + + State const state; + }; + + using LocaleFileEntry = std::pair<Path, State>; + + struct PathCompare + { + inline bool operator() (LocaleFileEntry const& left, LocaleFileEntry const& right) const + { + return left.first.filename().string() < right.first.filename().string(); + } + }; + + using LocaleFileStorage = boost::container::flat_set<LocaleFileEntry, PathCompare>; + using HashToFileNameStorage = std::unordered_map<std::string, std::string>; + using AppliedFileStorage = std::unordered_map<std::string, AppliedFileEntry>; + using DirectoryStorage = std::vector<UpdateFetcher::DirectoryEntry>; + using SQLUpdate = std::shared_ptr<std::string>; + + LocaleFileStorage GetFileList() const; + void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const; + + DirectoryStorage ReceiveIncludedDirectories() const; + AppliedFileStorage ReceiveAppliedFiles() const; + + SQLUpdate ReadSQLUpdate(Path const& file) const; + std::string CalculateHash(SQLUpdate const& query) const; + + uint32 Apply(Path const& path) const; + + void UpdateEntry(AppliedFileEntry const& entry, uint32 const speed = 0) const; + void RenameEntry(std::string const& from, std::string const& to) const; + void CleanUp(AppliedFileStorage const& storage) const; + + void UpdateState(std::string const& name, State const state) const; + + Path const _sourceDirectory; + + std::function<void(std::string const&)> const _apply; + std::function<void(Path const& path)> const _applyFile; + std::function<QueryResult(std::string const&)> const _retrieve; +}; + +#endif // UpdateFetcher_h__ diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 683c4de8eb8..63da20df2c7 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -49,6 +49,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/zmqpp + ${CMAKE_SOURCE_DIR}/dep/process ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models @@ -65,6 +66,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading + ${CMAKE_SOURCE_DIR}/src/server/shared/Updater ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_SOURCE_DIR}/src/server/game diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 15d08a903b9..50bb8d7646d 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -44,6 +44,7 @@ #include "WorldSocketMgr.h" #include "BattlenetServerManager.h" #include "Realm/Realm.h" +#include "DatabaseLoader.h" #include <openssl/opensslv.h> #include <openssl/crypto.h> #include <boost/asio/io_service.hpp> @@ -520,105 +521,16 @@ bool StartDB() { MySQL::Library_Init(); - std::string dbString; - uint8 asyncThreads, synchThreads; + // Load databases + DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE); + loader + .AddDatabase(HotfixDatabase, "Hotfix") + .AddDatabase(WorldDatabase, "World") + .AddDatabase(CharacterDatabase, "Character") + .AddDatabase(LoginDatabase, "Login"); - dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1)); - ///- Initialize the world database - if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str()); - return false; - } - - ///- Get character database info from configuration file - dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2)); - - ///- Initialize the Character database - if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str()); - return false; - } - - ///- Get hotfixes database info from configuration file - dbString = sConfigMgr->GetStringDefault("HotfixDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "Hotfixes database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("HotfixDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "Hotfixes database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("HotfixDatabase.SynchThreads", 2)); - - ///- Initialize the hotfixes database - if (!HotfixDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to the hotfix database %s", dbString.c_str()); - return false; - } - - ///- Get login database info from configuration file - dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1)); - ///- Initialise the login database - if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str()); + if (!loader.Load()) return false; - } ///- Get the realm Id from the configuration file realmHandle.Index = sConfigMgr->GetIntDefault("RealmID", 0); @@ -628,6 +540,7 @@ bool StartDB() return false; } + // Realm Handles QueryResult realmIdQuery = LoginDatabase.PQuery("SELECT `Region`,`Battlegroup` FROM `realmlist` WHERE `id`=%u", realmHandle.Index); if (!realmIdQuery) { diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 86d9dac2946..c1cdc4a7517 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -11,6 +11,7 @@ # PERFORMANCE SETTINGS # SERVER LOGGING # SERVER SETTINGS +# UPDATE SETTINGS # WARDEN SETTINGS # PLAYER INTERACTION # CREATURE SETTINGS @@ -1130,6 +1131,90 @@ FeatureSystem.CharacterUndelete.Cooldown = 2592000 ################################################################################################### ################################################################################################### +# UPDATE SETTINGS +# +# Updates.EnableDatabases +# Description: A mask that describes which databases shall be updated. +# +# Following flags are available +# DATABASE_LOGIN = 1, // Auth database +# DATABASE_CHARACTER = 2, // Character database +# DATABASE_WORLD = 4, // World database +# DATABASE_HOTFIX = 8, // Hotfixes database +# +# Default: 0 - (All Disabled) +# 4 - (Enable world only) +# 15 - (All enabled) + +Updates.EnableDatabases = 0 + +# +# Updates.SourcePath +# Description: The path to your TrinityCore source directory. +# If the path is left empty, built-in CMAKE_SOURCE_DIR is used. +# Example: "../TrinityCore" +# Default: "" + +Updates.SourcePath = "" + +# +# Updates.SourcePath +# Description: The path to your mysql cli binary. +# If the path is left empty, built-in path from cmake is used. +# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" +# "mysql.exe" +# "/usr/bin/mysql" +# Default: "" + +Updates.MySqlCLIPath = "" + +# +# Updates.AutoSetup +# Description: Auto populate empty databases. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.AutoSetup = 1 + +# +# Updates.Redundancy +# Description: Perform data redundancy checks through hashing +# to detect changes on sql updates and reapply it. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.Redundancy = 1 + +# +# Updates.ArchivedRedundancy +# Description: Check hashes of archived updates (slows down startup). +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Updates.ArchivedRedundancy = 0 + +# +# Updates.AllowRehash +# Description: Inserts the current file hash in the database if it is left empty. +# Useful if you want to mark a file as applied but you don't know its hash. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.AllowRehash = 1 + +# +# Updates.CleanDeadRef +# Description: Cleans dead/ orphaned references that occure if a update was deleted or renamed and edited. +# Disable this if you want to know if the database is in a possible "dirty state". +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Updates.CleanDeadRef = 1 + +# +################################################################################################### + +################################################################################################### # WARDEN SETTINGS # # Warden.Enabled @@ -3224,6 +3309,7 @@ Logger.root=5,Console Server Logger.server=3,Console Server Logger.commands.gm=3,Console GM Logger.sql.sql=5,Console DBErrors +Logger.sql.updates=3,Console Server #Logger.achievement=3,Console Server #Logger.ahbot=3,Console Server |